Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/genkit-ai/genkit/llms.txt

Use this file to discover all available pages before exploring further.

Retrieval-Augmented Generation (RAG) extends a model’s knowledge by finding and injecting relevant documents into the prompt at query time. Instead of relying solely on what was in the model’s training data, your application can search a private document corpus—product docs, support tickets, internal wikis—and pass the most relevant excerpts to the model. The typical RAG pipeline has two phases:
  1. Indexing — Chunk documents, embed them into vectors, and store them in a vector database.
  2. Retrieval + Generation — Embed the user’s query, retrieve the most similar documents, and include them in the prompt.
Genkit provides three primitives that map directly onto this pipeline: indexers, embedders, and retrievers.

The three RAG primitives

Embedders

An embedder converts text (or other content) into a numeric vector for similarity search.
// TypeScript — embed a piece of text
const embeddings = await ai.embed({
  embedder: 'googleai/gemini-embedding-001',
  content: 'How do I reset my password?',
});
// embeddings[0].embedding → number[]

Indexers

An indexer takes documents and stores them in a vector database.
// TypeScript — define a custom indexer backed by your vector DB
const myIndexer = ai.defineIndexer(
  { name: 'myDocs' },
  async (docs) => {
    for (const doc of docs) {
      const [embedding] = await ai.embed({
        embedder: 'googleai/gemini-embedding-001',
        content: doc.text(),
      });
      await vectorDB.upsert({
        id: doc.metadata?.id,
        vector: embedding.embedding,
        payload: { text: doc.text(), ...doc.metadata },
      });
    }
  }
);

Retrievers

A retriever takes a query and returns the most relevant documents.
// TypeScript — define a custom retriever
const myRetriever = ai.defineRetriever(
  { name: 'myDocs' },
  async (query, options) => {
    const [queryEmbedding] = await ai.embed({
      embedder: 'googleai/gemini-embedding-001',
      content: query.text(),
    });
    const results = await vectorDB.query({
      vector: queryEmbedding.embedding,
      topK: options?.k ?? 5,
    });
    return {
      documents: results.map((r) =>
        Document.fromText(r.payload.text, r.payload)
      ),
    };
  }
);

Indexing documents

Use ai.index() to store documents via any registered indexer:
import { Document } from '@genkit-ai/ai';

const docs = [
  Document.fromText('Genkit is an open-source AI framework.', { source: 'overview.md' }),
  Document.fromText('Flows are type-safe, observable AI functions.', { source: 'flows.md' }),
  Document.fromText('Use ai.generate() to call any supported model.', { source: 'models.md' }),
];

await ai.index({
  indexer: myIndexer,
  documents: docs,
});

Retrieving documents

Use ai.retrieve() to fetch relevant documents at query time:
const relevantDocs = await ai.retrieve({
  retriever: myRetriever,
  query: 'How do flows work in Genkit?',
  options: { k: 3 }, // number of results to return
});

console.log(relevantDocs.map((d) => d.text()));

End-to-end RAG flow

Here is a complete example that combines indexing and retrieval into a working Q&A application:
import { genkit, z } from 'genkit';
import { googleAI } from '@genkit-ai/google-genai';
import { Document } from '@genkit-ai/ai';

const ai = genkit({ plugins: [googleAI()] });

// --- Indexing phase (run once, e.g., in a build script) ---

export async function indexDocs(filePaths: string[]) {
  const docs = await Promise.all(
    filePaths.map(async (path) => {
      const text = await fs.readFile(path, 'utf-8');
      return Document.fromText(text, { source: path });
    })
  );

  await ai.index({ indexer: myIndexer, documents: docs });
  console.log(`Indexed ${docs.length} documents.`);
}

// --- Retrieval + generation phase (run on every user query) ---

const answerQuestion = ai.defineFlow(
  {
    name: 'answerQuestion',
    inputSchema: z.string(),
    outputSchema: z.string(),
  },
  async (question) => {
    // 1. Retrieve relevant documents
    const docs = await ai.retrieve({
      retriever: myRetriever,
      query: question,
      options: { k: 5 },
    });

    // 2. Build an augmented prompt
    const context = docs.map((d) => d.text()).join('\n\n');

    // 3. Generate an answer grounded in the retrieved context
    const response = await ai.generate({
      model: 'googleai/gemini-2.5-flash',
      system:
        'You are a helpful assistant. Answer questions using ONLY the '
        + 'provided context. If the context does not contain the answer, '
        + 'say you do not know.',
      prompt: `Context:\n${context}\n\nQuestion: ${question}`,
    });

    return response.text;
  }
);

// Usage
const answer = await answerQuestion('How do flows work in Genkit?');
console.log(answer);
Alternatively, pass retrieved docs directly via the docs option on generate() and let Genkit format them for you:
const response = await ai.generate({
  model: 'googleai/gemini-2.5-flash',
  prompt: question,
  docs: relevantDocs,  // injected as context automatically
});

Plugin-provided vector stores

In production you will use a plugin-provided indexer and retriever rather than hand-rolling one. Genkit plugins are available for the most popular vector stores:
Vector StorePluginNotes
Firebase / Firestore@genkit-ai/firebaseServerless, no infrastructure to manage.
Vertex AI Vector Search@genkit-ai/google-genaiManaged, high scale.
Pineconegenkitx-pineconeFully managed vector database.
Chromagenkitx-chromadbOpen-source, great for local dev.
Local dev store@genkit-ai/dev-local-vectorstoreIn-process, no setup needed for local testing.

Example: local dev vector store

import { devLocalVectorstore } from '@genkit-ai/dev-local-vectorstore';
import { googleAI } from '@genkit-ai/google-genai';

const ai = genkit({
  plugins: [
    googleAI(),
    devLocalVectorstore([
      {
        indexName: 'docs',
        embedder: 'googleai/gemini-embedding-001',
      },
    ]),
  ],
});

// The plugin registers indexer and retriever automatically:
const indexer  = ai.lookup('indexer',  'devLocalVectorstore/docs');
const retriever = ai.lookup('retriever', 'devLocalVectorstore/docs');

Example: Firebase Firestore vector store

import { firebase, firestoreRetriever } from '@genkit-ai/firebase';

const retriever = firestoreRetriever(ai, {
  collection: 'documents',
  vectorField: 'embedding',
  contentField: 'text',
  embedder: 'googleai/gemini-embedding-001',
});
See Firebase plugin and Vertex AI plugin for full configuration options.

Defining a simple retriever

If you already have data in a database and just need to map query results to Document objects, defineSimpleRetriever is a convenient shorthand:
const sqlRetriever = ai.defineSimpleRetriever(
  {
    name: 'sqlDocs',
    configSchema: z.object({ limit: z.number().default(5) }),
    // Map each row to its text content and optional metadata
    content: (row) => row.content,
    metadata: (row) => ({ id: row.id, title: row.title }),
  },
  async (query, config) => {
    return db.query(
      'SELECT id, title, content FROM docs ORDER BY similarity($1) LIMIT $2',
      [query.text(), config.limit]
    );
  }
);

Next steps

Firebase Plugin

Firestore-backed vector store and Firebase deployment.

Vertex AI Plugin

Vertex AI Vector Search and Gemini embeddings.

Flows

Wrap RAG logic in traced, deployable flows.

Evaluation

Measure RAG pipeline quality with built-in evaluators.

Build docs developers (and LLMs) love