> ## Documentation Index
> Fetch the complete documentation index at: https://vlyai-1c28d863.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Vector search

> Semantic search via embeddings, built into Convex. Pair with OpenAI / other embedding providers.

Convex includes native vector search — no Pinecone or Qdrant required for most apps.

## Setup

### 1. Add a vector index to the schema

```typescript convex/schema.ts theme={null}
documents: defineTable({
  title:     v.string(),
  body:      v.string(),
  ownerId:   v.id("users"),
  embedding: v.array(v.number()),
})
  .vectorIndex("by_embedding", {
    vectorField:  "embedding",
    dimensions:   1536,             // OpenAI text-embedding-3-small
    filterFields: ["ownerId"],
  })
```

### 2. Embed and store

```typescript convex/documents.ts theme={null}
import { action } from "./_generated/server";
import { api } from "./_generated/api";

export const indexDocument = action({
  args: { id: v.id("documents") },
  handler: async (ctx, { id }) => {
    const doc = await ctx.runQuery(api.documents.get, { id });
    if (!doc) return;

    const embedding = await embedText(`${doc.title}\n\n${doc.body}`);
    await ctx.runMutation(api.documents.setEmbedding, { id, embedding });
  },
});
```

### 3. Search

```typescript convex/documents.ts theme={null}
export const search = action({
  args: { query: v.string(), ownerId: v.id("users") },
  handler: async (ctx, { query, ownerId }) => {
    const queryEmbedding = await embedText(query);

    const results = await ctx.vectorSearch("documents", "by_embedding", {
      vector: queryEmbedding,
      limit:  10,
      filter: q => q.eq("ownerId", ownerId),
    });

    // results: [{ _id, _score }, ...]
    const docs = await Promise.all(
      results.map(r => ctx.runQuery(api.documents.get, { id: r._id }))
    );
    return docs.filter(Boolean);
  },
});
```

## Embedding providers

Common choices:

| Provider | Model | Dimensions |
| - | - | - |
| [OpenAI](/integrations/openai) | text-embedding-3-small | 1536 |
| OpenAI | text-embedding-3-large | 3072 |
| Cohere | embed-v3-english | 1024 |
| Voyage AI | voyage-2 | 1024 |

Pick one and stick with it — mixing dimensions across the same index doesn't work.

## Tips

<Tip>
  **Re-embed when content changes.** If you edit a document's body, queue a re-embed (typically via a [scheduled action](/convex/scheduled-functions) or directly in the mutation that updated the body).
</Tip>

<Tip>
  **Use filter fields aggressively.** Vector search returns the most-similar items; filter to the right scope (per-user, per-team) before vector matching.
</Tip>

## Related

<CardGroup cols={3}>
  <Card title="Schema" icon="database" href="/convex/schema">
    Vector index syntax.
  </Card>

  <Card title="OpenAI" icon="sparkles" href="/integrations/openai">
    Embedding provider.
  </Card>

  <Card title="AI chatbot recipe" icon="message-circle" href="/recipes/ai-chatbot">
    RAG pattern using vector search.
  </Card>
</CardGroup>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.