From gocallum-nextjs16-agent-skills
Guides setup and usage of Upstash Vector DB for semantic search, with namespaces and MixBread AI embeddings. Useful when building vector search features on Vercel.
How this skill is triggered — by the user, by Claude, or both
Slash command
/gocallum-nextjs16-agent-skills:upstash-vector-db-skillsThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
- Docs: https://upstash.com/docs/vector
UPSTASH_VECTOR_REST_URL and UPSTASH_VECTOR_REST_TOKEN to .envpnpm add @upstash/vector
UPSTASH_VECTOR_REST_URL=your_url
UPSTASH_VECTOR_REST_TOKEN=your_token
import { Index } from "@upstash/vector";
const index = new Index({
url: process.env.UPSTASH_VECTOR_REST_URL,
token: process.env.UPSTASH_VECTOR_REST_TOKEN,
});
When using an embedding model in the index, text is embedded automatically:
// 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" } },
]);
// 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);
});
Namespaces partition a single index into isolated subsets. Useful for multi-tenant or multi-domain apps.
// 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");
// 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" });
}
}
// 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"]);
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)If using MixBread as your embedding provider:
index.upsert() / index.query() with text directly..env.local).namespace("user-123") for per-user search.topK reasonable (5–10 typically sufficient).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);
}
}
const docs = await index.query({ data: userQuestion, topK: 3 });
const context = docs.map((d) => d.metadata?.text).join("\n");
// Pass context to LLM
Use namespaces to isolate each tenant's vectors:
const userNamespace = `tenant-${userId}`;
await index.namespace(userNamespace).upsert({ id, data, metadata });
// Queries only see that tenant's data
For bulk imports, upsert in batches:
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}`);
}
"".npx claudepluginhub joshuarweaver/cascade-code-languages-misc-1 --plugin gocallum-nextjs16-agent-skillsGuides usage of Upstash Vector: install SDK, connect, upsert vectors, query, and manage namespaces. Covers TS SDK methods and features like filtering, hybrid/sparse indexes.
Implements Cloudflare Vectorize vector database for semantic search, RAG, and AI apps on Workers. Manages indexes, vector CRUD, metadata filtering, embeddings from Workers AI or OpenAI.
Implements vector search solutions using Pinecone, Weaviate, Qdrant, Milvus, and pgvector. Covers embedding strategies, indexing, and hybrid search for RAG and recommendation systems.