home / skills / gocallum / nextjs16-agent-skills / upstash-vector-db-skills

upstash-vector-db-skills skill

/skills/upstash-vector-db-skills

This skill helps you set up Upstash Vector DB for semantic search, namespaces, and MixBread embeddings, accelerating vector-based apps.

npx playbooks add skill gocallum/nextjs16-agent-skills --skill upstash-vector-db-skills

Review the files below or copy the command above to add this skill to your agents.

Files (1)
SKILL.md
7.1 KB
---
name: upstash-vector-db-skills
description: Upstash Vector DB setup, semantic search, namespaces, and embedding models (MixBread preferred). Use when building vector search features on Vercel.
---

## Links

- Docs: https://upstash.com/docs/vector
- Getting Started: https://upstash.com/docs/vector/overall/getstarted
- Semantic Search Tutorial: https://upstash.com/docs/vector/tutorials/semantic_search
- Namespaces: https://upstash.com/docs/vector/features/namespaces
- Embedding Models: https://upstash.com/docs/vector/features/embeddingmodels
- MixBread AI: https://www.mixbread.ai/ (preferred embedding provider)

## Quick Setup

### 1. Create Vector Index (Upstash Console)

- Go to [Upstash Console](https://console.upstash.com/)
- Create Vector Index: name, region (closest to app), type (Dense for semantic search)
- Select embedding model: **MixBread AI recommended** (or use Upstash built-in models)
- Copy `UPSTASH_VECTOR_REST_URL` and `UPSTASH_VECTOR_REST_TOKEN` to `.env`

### 2. Install SDK

```sh
pnpm add @upstash/vector
```

### 3. Environment

```env
UPSTASH_VECTOR_REST_URL=your_url
UPSTASH_VECTOR_REST_TOKEN=your_token
```

## Code Examples

### Initialize Client (Node.js / TypeScript)

```typescript
import { Index } from "@upstash/vector";

const index = new Index({
  url: process.env.UPSTASH_VECTOR_REST_URL,
  token: process.env.UPSTASH_VECTOR_REST_TOKEN,
});
```

### Upsert Documents (Auto-Embed)

When using an embedding model in the index, text is embedded automatically:

```typescript
// Single document
await index.upsert({
  id: "doc-1",
  data: "Upstash provides serverless vector database solutions.",
  metadata: { source: "docs", category: "intro" },
});

// Batch
await index.upsert([
  { id: "doc-2", data: "Vector search powers semantic similarity.", metadata: { source: "docs" } },
  { id: "doc-3", data: "MixBread AI provides high-quality embeddings.", metadata: { source: "blog" } },
]);
```

### Query / Semantic Search

```typescript
// Semantic search with auto-embedding
const results = await index.query({
  data: "What is semantic search?",
  topK: 5,
  includeMetadata: true,
});

results.forEach((result) => {
  console.log(`ID: ${result.id}, Score: ${result.score}, Metadata:`, result.metadata);
});
```

### Using Namespaces (Data Isolation)

Namespaces partition a single index into isolated subsets. Useful for multi-tenant or multi-domain apps.

```typescript
// Upsert in namespace "blog"
await index.namespace("blog").upsert({
  id: "post-1",
  data: "Next.js tutorial for Vercel deployment",
  metadata: { author: "user-123" },
});

// Query only "blog" namespace
const blogResults = await index.namespace("blog").query({
  data: "Vercel deployment",
  topK: 3,
  includeMetadata: true,
});

// List all namespaces
const namespaces = await index.listNamespaces();
console.log(namespaces);

// Delete namespace
await index.deleteNamespace("blog");
```

### Full Semantic Search Example (Vercel Function)

```typescript
// api/search.ts (Vercel Edge Function or Serverless Function)
import { Index } from "@upstash/vector";

export const config = {
  runtime: "nodejs", // or "edge"
};

const index = new Index({
  url: process.env.UPSTASH_VECTOR_REST_URL,
  token: process.env.UPSTASH_VECTOR_REST_TOKEN,
});

export default async function handler(req, res) {
  if (req.method !== "POST") {
    return res.status(405).json({ error: "Method not allowed" });
  }

  const { query, namespace = "", topK = 5 } = req.body;

  try {
    const searchIndex = namespace ? index.namespace(namespace) : index;
    const results = await searchIndex.query({
      data: query,
      topK,
      includeMetadata: true,
    });

    return res.status(200).json({ results });
  } catch (error) {
    console.error("Search error:", error);
    return res.status(500).json({ error: "Search failed" });
  }
}
```

### Index Operations

```typescript
// Reset (clear all vectors in index or namespace)
await index.reset();

// Or reset a specific namespace
await index.namespace("old-data").reset();

// Delete a single vector
await index.delete("doc-1");

// Delete multiple vectors
await index.delete(["doc-1", "doc-2", "doc-3"]);
```

## Embedding Models

### Available in Upstash

- `BAAI/bge-large-en-v1.5` (1024 dim, best performance, ~64.23 MTEB score)
- `BAAI/bge-base-en-v1.5` (768 dim, good balance)
- `BAAI/bge-small-en-v1.5` (384 dim, lightweight)
- `BAAI/bge-m3` (1024 dim, sparse + dense hybrid)

### Recommended: MixBread AI

If using MixBread as your embedding provider:

1. Create a MixBread API key at https://www.mixbread.ai/
2. When creating your Upstash index, select **MixBread** as the embedding model.
3. MixBread handles tokenization and semantic quality automatically.
4. No extra setup needed in your code; use `index.upsert()` / `index.query()` with text directly.

## Best Practices

### For Vercel Deployment

- Store credentials in Vercel Environment Variables (project settings or `.env.local`).
- Use Edge Functions or Serverless Functions for low-latency access.
- Implement request rate limiting to stay within Upstash quotas.

### Namespace Strategy

- Use namespaces to isolate data by tenant, domain, or use case.
- Example: `namespace("user-123")` for per-user search.
- Clean up old namespaces to avoid storage bloat.

### Query Performance

- Keep `topK` reasonable (5–10 typically sufficient).
- Use metadata filtering to pre-filter results if possible.
- Upstash is eventually consistent; expect slight delays after upserts.

### Error Handling

```typescript
try {
  const results = await index.query({
    data: userQuery,
    topK: 5,
    includeMetadata: true,
  });
} catch (error) {
  if (error.status === 401) {
    console.error("Invalid credentials");
  } else if (error.status === 429) {
    console.error("Rate limited");
  } else {
    console.error("Query error:", error);
  }
}
```

## Common Patterns

### RAG (Retrieval Augmented Generation)

1. Upsert documents / knowledge base into Upstash.
2. On user query, retrieve top-k similar docs via semantic search.
3. Pass retrieved docs + user query to LLM for better context.

```typescript
const docs = await index.query({ data: userQuestion, topK: 3 });
const context = docs.map((d) => d.metadata?.text).join("\n");
// Pass context to LLM
```

### Multi-Tenant Search

Use namespaces to isolate each tenant's vectors:

```typescript
const userNamespace = `tenant-${userId}`;
await index.namespace(userNamespace).upsert({ id, data, metadata });
// Queries only see that tenant's data
```

### Batch Indexing

For bulk imports, upsert in batches:

```typescript
const batchSize = 100;
for (let i = 0; i < documents.length; i += batchSize) {
  const batch = documents.slice(i, i + batchSize);
  await index.upsert(batch);
  console.log(`Indexed batch ${i / batchSize + 1}`);
}
```

## Troubleshooting

- **No results returned**: Ensure documents are indexed and embedding model is active.
- **Slow queries**: Check quota limits; consider upgrading plan or reducing dataset size.
- **Stale data**: Upstash is eventually consistent; wait 1–2 seconds before querying new inserts.
- **Namespace not working**: Ensure namespace exists (created on first upsert) or use the default `""`.

Overview

This skill provides a compact guide and code-ready patterns for setting up Upstash Vector DB for semantic search on Vercel. It covers index creation, MixBread embeddings, namespaces for multi-tenant isolation, and sample Vercel function code. Use it to implement fast, serverless vector search with practical deployment advice.

How this skill works

Initialize an Index client with your UPSTASH_VECTOR_REST_URL and UPSTASH_VECTOR_REST_TOKEN and let the index handle embedding when an embedding model (MixBread recommended) is selected. Upsert accepts raw text and metadata and the index returns embedding vectors automatically. Query with a text input to perform semantic search, optionally scoping to a namespace for isolated datasets.

When to use it

  • Build semantic search or RAG pipelines on Vercel using serverless or edge functions.
  • Isolate tenant or domain data using namespaces in a single index.
  • Quickly prototype vector search without managing embedding infra (MixBread auto-embed).
  • Batch-import document collections for retrieval and QA use cases.
  • Keep low-latency search in environments with ephemeral serverless instances.

Best practices

  • Select MixBread or an appropriate embedding model when creating the index to enable auto-embedding.
  • Store UPSTASH credentials in Vercel Environment Variables or .env.local, never in source code.
  • Use namespaces per tenant or domain and clean up unused namespaces to avoid storage bloat.
  • Keep topK small (5–10) and apply metadata filters to reduce compute and improve relevance.
  • Implement rate limiting and error handling for 401/429 errors and expect slight eventual consistency delays.

Example use cases

  • A Vercel Edge Function that accepts a user query, queries Upstash, and returns top-k results with metadata.
  • Multi-tenant knowledge base where each user or customer uses namespace("tenant-{id}") to isolate vectors.
  • RAG pipeline: fetch top-k related docs from Upstash and pass concatenated context to an LLM.
  • Bulk migration: batch upsert large document sets with chunked batches to avoid timeouts and quota spikes.
  • Temporary search indices for ephemeral projects or environments, then reset or delete namespaces when done.

FAQ

Do I need to call an embedding API in my code?

No. If you select an embedding model (MixBread or Upstash models) when creating the index, upsert() will auto-embed the text for you.

How do I isolate data for each tenant?

Use index.namespace("tenant-id") to upsert and query vectors scoped to that namespace. Namespaces are created on first upsert and can be listed or deleted via the SDK.