Guides

Embedding Providers

Last updated by
Harlan Wilton
in chore: sync.

What are Embeddings?

Embeddings are numerical representations (vectors) of text that capture semantic meaning. They enable semantic search - finding content by meaning rather than just keyword matching.

Dual-Provider Architecture

Nuxt Ask AI supports separate providers for build-time and runtime environments.

Why?

  • Build: Use local transformers.js (free, reproducible) or cloud APIs
  • Runtime: Use cloud APIs or Workers AI (fast, low latency)
  • Flexibility: Mix providers (e.g., local build, cloud runtime)

Configuration:

nuxt.config.ts
export default defineNuxtConfig({
  aiSearch: {
    embeddings: {
      model: 'bge-small-en-v1.5',  // Base model name (provider-agnostic)
      buildProvider: {
        preset: 'transformers.js'   // For prerender/build
      },
      runtimeProvider: {
        preset: 'openai',            // For search queries at runtime
        apiKey: process.env.OPENAI_API_KEY
      }
    }
  }
})

Model Resolution:

  • Base model: bge-small-en-v1.5
  • Build (transformers.js): Xenova/bge-small-en-v1.5
  • Runtime (openai): text-embedding-3-small
  • Resolved via resolveModelForPreset(baseModel, preset)

Available Providers

All providers unified through AI SDK (ai package from Vercel).

transformers.js (Default)

Local ONNX models via @built-in-ai/transformers-js.

nuxt.config.ts
export default defineNuxtConfig({
  aiSearch: {
    embeddings: {
      model: 'bge-small-en-v1.5',
      buildProvider: {
        preset: 'transformers.js'
      },
      runtimeProvider: {
        preset: 'transformers.js'
      }
    }
  }
})

Pros:

  • ✅ Free, no API keys
  • ✅ Works offline
  • ✅ Privacy-preserving

Cons:

  • ❌ Slower build (~30-60s for 100 pages)
  • ❌ Model download required (~80MB, cached)

OpenAI

OpenAI embeddings via @ai-sdk/openai.

nuxt.config.ts
export default defineNuxtConfig({
  aiSearch: {
    embeddings: {
      model: 'text-embedding-3-small',
      buildProvider: {
        preset: 'openai',
        apiKey: process.env.OPENAI_API_KEY
      },
      runtimeProvider: {
        preset: 'openai',
        apiKey: process.env.OPENAI_API_KEY
      }
    }
  }
})

Pros:

  • ✅ Highest quality
  • ✅ Fast builds (~10-20s for 100 pages)

Cons:

  • ❌ Costs money per build
  • ❌ Requires API key

Ollama

Local Ollama server via ollama-ai-provider-v2.

nuxt.config.ts
export default defineNuxtConfig({
  aiSearch: {
    embeddings: {
      model: 'nomic-embed-text',
      buildProvider: {
        preset: 'ollama',
        baseURL: 'http://localhost:11434'
      },
      runtimeProvider: {
        preset: 'ollama',
        baseURL: 'http://localhost:11434'
      }
    }
  }
})

Pros:

  • ✅ Free, open source
  • ✅ Privacy-preserving
  • ✅ Customizable models

Cons:

  • ❌ Requires Ollama installation
  • ❌ Model download required

Google

Google embeddings via @ai-sdk/google.

nuxt.config.ts
export default defineNuxtConfig({
  aiSearch: {
    embeddings: {
      model: 'text-embedding-004',
      buildProvider: {
        preset: 'google',
        apiKey: process.env.GOOGLE_API_KEY
      }
    }
  }
})

Mistral

Mistral embeddings via @ai-sdk/mistral.

nuxt.config.ts
export default defineNuxtConfig({
  aiSearch: {
    embeddings: {
      model: 'mistral-embed',
      buildProvider: {
        preset: 'mistral',
        apiKey: process.env.MISTRAL_API_KEY
      }
    }
  }
})

Cohere

Cohere embeddings via @ai-sdk/cohere.

nuxt.config.ts
export default defineNuxtConfig({
  aiSearch: {
    embeddings: {
      model: 'embed-english-v3.0',
      buildProvider: {
        preset: 'cohere',
        apiKey: process.env.COHERE_API_KEY
      }
    }
  }
})

Anthropic (Voyage)

Anthropic (Voyage) embeddings via @ai-sdk/anthropic.

nuxt.config.ts
export default defineNuxtConfig({
  aiSearch: {
    embeddings: {
      model: 'voyage-2',
      buildProvider: {
        preset: 'anthropic',
        apiKey: process.env.ANTHROPIC_API_KEY
      }
    }
  }
})

Workers AI (Cloudflare)

Cloudflare Workers AI via workers-ai-provider (runtime only).

nuxt.config.ts
export default defineNuxtConfig({
  aiSearch: {
    embeddings: {
      model: 'bge-base-en-v1.5',
      buildProvider: {
        preset: 'transformers.js'  // Build locally
      },
      runtimeProvider: {
        preset: 'workers-ai'        // Runtime on Workers
      }
    }
  }
})

Note: Workers AI requires Cloudflare Workers/Pages deployment.

Choosing a Provider

For Development

transformers.js

  • Free, no setup required
nuxt.config.ts
export default defineNuxtConfig({
  aiSearch: {
    embeddings: {
      model: 'bge-small-en-v1.5',
      buildProvider: { preset: 'transformers.js' },
      runtimeProvider: { preset: 'transformers.js' }
    }
  }
})

For Production

Cost-effective and fast:

nuxt.config.ts
export default defineNuxtConfig({
  aiSearch: {
    embeddings: {
      model: 'bge-small-en-v1.5',
      buildProvider: {
        preset: 'transformers.js'  // Free local build
      },
      runtimeProvider: {
        preset: 'openai',           // Fast cloud runtime
        apiKey: process.env.OPENAI_API_KEY
      }
    }
  }
})

Option 2: Cloud Build + Cloud Runtime

Fastest builds:

nuxt.config.ts
export default defineNuxtConfig({
  aiSearch: {
    embeddings: {
      model: 'text-embedding-3-small',
      buildProvider: {
        preset: 'openai',
        apiKey: process.env.OPENAI_API_KEY
      },
      runtimeProvider: {
        preset: 'openai',
        apiKey: process.env.OPENAI_API_KEY
      }
    }
  }
})

Option 3: Cloudflare Workers

Local build + Workers AI runtime:

nuxt.config.ts
export default defineNuxtConfig({
  aiSearch: {
    embeddings: {
      model: 'bge-base-en-v1.5',
      buildProvider: {
        preset: 'transformers.js'
      },
      runtimeProvider: {
        preset: 'workers-ai'
      },
      vectorDatabase: {
        provider: 'cloudflare-vectorize',
        indexName: 'ai-search'
      }
    }
  }
})

Model Mappings

Provider-specific model names are resolved automatically:

Base Modeltransformers.jsworkers-ai
bge-small-en-v1.5Xenova/bge-small-en-v1.5@cf/baai/bge-small-en-v1.5
bge-base-en-v1.5Xenova/bge-base-en-v1.5@cf/baai/bge-base-en-v1.5
embeddinggemma-300monnx-community/embeddinggemma-300m-ONNX@cf/google/embeddinggemma-300m

Dimension Detection

Dimensions are auto-detected via:

  1. Check explicit dimensions parameter
  2. Lookup via getModelDimensions(baseModel)
  3. Test embedding: embed({ model, value: 'test' })
  4. Validate: throw if mismatch
nuxt.config.ts
export default defineNuxtConfig({
  aiSearch: {
    embeddings: {
      model: 'bge-small-en-v1.5',
      dimensions: 384,  // Auto-detected if omitted
      buildProvider: { preset: 'transformers.js' }
    }
  }
})

Environment Variables

.env
OPENAI_API_KEY=sk-...
GOOGLE_API_KEY=...
MISTRAL_API_KEY=...
COHERE_API_KEY=...
ANTHROPIC_API_KEY=...
OLLAMA_BASE_URL=http://localhost:11434

Troubleshooting

Model Download Fails (transformers.js)

# Clear cache and retry
rm -rf node_modules/.cache/@huggingface/transformers
pnpm generate

Out of Memory

# Increase Node.js memory
NODE_OPTIONS=--max-old-space-size=4096 pnpm generate

API Key Not Found

# Verify environment variable
echo $OPENAI_API_KEY

# Or check .env file
cat .env | grep OPENAI_API_KEY

Dimension Mismatch

Error: expected 384, got 1536 dimensions

Fix: Set explicit dimensions in config:

nuxt.config.ts
export default defineNuxtConfig({
  aiSearch: {
    embeddings: {
      model: 'text-embedding-3-small',
      dimensions: 1536,  // Must match model
      buildProvider: { preset: 'openai', apiKey: '...' }
    }
  }
})

Next Steps

Did this page help you?