Skip to content

File Search

Gunpal Jain edited this page Nov 15, 2026 · 1 revision

File Search

File Search is managed retrieval-augmented generation (RAG) on the Gemini API. You create a File Search store, add documents to it, and Google chunks, embeds and indexes them. You then give the store to the FileSearch tool, and the model grounds its answers on your documents.

The SDK exposes it through FileSearchStoresClient (namespace GenerativeAI.Clients).

Platform Support
Gemini API Yes
Vertex AI No. Every FileSearchStoresClient method and GenerativeModel.UseFileSearch throw NotSupportedException on Vertex AI. Use the Vertex RAG Engine there.

Prerequisites

  • NuGet package: Google_GenerativeAI
  • A Gemini API key. See Authentication.
using GenerativeAI;
using GenerativeAI.Clients;
using GenerativeAI.Types;

var googleAi = new GoogleAi(apiKey);
FileSearchStoresClient stores = googleAi.CreateFileSearchStoresClient();

Typical flow

  1. Create a store with CreateFileSearchStoreAsync.
  2. Add files with UploadToFileSearchStoreAsync / UploadStreamToFileSearchStoreAsync, or import a file that is already uploaded through the Files API with ImportFileAsync.
  3. Wait for indexing with WaitForOperationAsync.
  4. Pass the store name to the FileSearch tool, for example with GenerativeModel.UseFileSearch.

Create, get, list and delete stores

// Display name and embedding model are optional.
FileSearchStore store = await stores.CreateFileSearchStoreAsync("product-docs");
Console.WriteLine(store.Name); // "fileSearchStores/..."

var same = await stores.GetFileSearchStoreAsync(store.Name!);
Console.WriteLine($"{same.ActiveDocumentsCount} active, {same.PendingDocumentsCount} pending");

// One page at a time...
var page = await stores.ListFileSearchStoresAsync(pageSize: 20);
// ...or every store.
await foreach (var s in stores.ListAllFileSearchStoresAsync())
    Console.WriteLine($"{s.Name}: {s.DisplayName}");

// force: true also deletes the documents in the store.
await stores.DeleteFileSearchStoreAsync(store.Name!, force: true);

Store names can be given as fileSearchStores/{id} or just {id}.

Upload files into a store

Upload a local file directly. The MIME type is inferred from the extension if you don't set it:

var operation = await stores.UploadToFileSearchStoreAsync(store.Name!, "docs/manual.pdf",
    new UploadToFileSearchStoreConfig
    {
        DisplayName = "manual.pdf",
        CustomMetadata = new List<CustomMetadata> { new("product") { StringValue = "router-x" } },
        ChunkingConfig = new ChunkingConfig
        {
            WhiteSpaceConfig = new WhiteSpaceConfig { MaxTokensPerChunk = 400, MaxOverlapTokens = 40 }
        }
    },
    progressCallback: p => Console.WriteLine($"{p:F0}%"));

operation = await stores.WaitForOperationAsync(operation, timeout: TimeSpan.FromMinutes(5));
Console.WriteLine(operation.Response?.DocumentName);

Or upload from a stream (the stream is disposed once the upload finishes):

using var stream = new MemoryStream(Encoding.UTF8.GetBytes("Project Bluebird started in 2019."));
var op = await stores.UploadStreamToFileSearchStoreAsync(store.Name!, stream, "text/plain",
    new UploadToFileSearchStoreConfig { DisplayName = "bluebird.txt" });
op = await stores.WaitForOperationAsync(op);

Import a file from the Files API

If you already uploaded the file with the Files API (see Files Client), import it by name:

var importOp = await stores.ImportFileAsync(store.Name!, "files/abc123",
    new ImportFileConfig
    {
        CustomMetadata = new List<CustomMetadata> { new("year") { NumericValue = 2024 } }
    });
importOp = await stores.WaitForOperationAsync(importOp);

WaitForOperationAsync polls every 2 seconds by default and throws TimeoutException after 10 minutes unless you pass other values. You can also poll yourself with GetOperationAsync(operationName). Check FileSearchOperation.Error when Done is true.

Manage documents

await foreach (var doc in stores.ListAllDocumentsAsync(store.Name!))
    Console.WriteLine($"{doc.Name} {doc.DisplayName} {doc.State}");

var document = await stores.GetDocumentAsync("fileSearchStores/my-store/documents/my-doc");

// force: true also deletes the document's chunks.
await stores.DeleteDocumentAsync(document.Name!, force: true);

DownloadMediaAsync(mediaId) downloads media referenced by File Search grounding metadata (fileSearchStores/{store}/media/{blob}).

Use File Search in generation

With GenerativeModel

UseFileSearch adds a FileSearch tool to every request of the model:

var model = googleAi.CreateGenerativeModel(GoogleAIModels.Gemini38Flash);
model.UseFileSearch(store.Name!);

var response = await model.GenerateContentAsync("What year did Project Bluebird start?");
Console.WriteLine(response.Text());

The other overload takes topK and an AIP-160 metadataFilter over the documents' custom metadata:

model.UseFileSearch(new[] { store.Name! }, topK: 5, metadataFilter: "product = \"router-x\"");

You can also build the tool yourself (Tool.FileSearch with a FileSearch object that has FileSearchStoreNames, TopK and MetadataFilter).

With the Interactions API

var interactions = googleAi.CreateInteractionsClient();
var result = await interactions.CreateAsync(new CreateInteractionRequest
{
    Model = InteractionModels.Gemini38Flash,
    Input = "What year did Project Bluebird start?",
    Tools = new List<InteractionTool>
    {
        new InteractionFileSearchTool { FileSearchStoreNames = new List<string> { store.Name! } }
    }
});
Console.WriteLine(result.OutputText);

See Interactions API.

Error handling

  • API errors are thrown as GenerativeAI.Exceptions.ApiException (ErrorCode, ErrorStatus, ErrorMessage). 402/429 means the project has no quota or billing for File Search right now.
  • NotSupportedException is thrown when the client or model uses Vertex AI.
  • TimeoutException is thrown by WaitForOperationAsync when indexing takes longer than the timeout.
try
{
    var store = await stores.CreateFileSearchStoreAsync("docs");
}
catch (ApiException ex) when (ex.ErrorCode is 402 or 429)
{
    Console.WriteLine($"File Search is not available right now: {ex.ErrorMessage}");
}

Related pages

Clone this wiki locally