> ## AI Agent Context > Get the complete documentation index at: https://aistudio.google.com/docs/llms.txt > Use this file to discover all available pages. > For the full documentation in a single file, fetch: https://aistudio.google.com/docs/llms-full.txt # File search The Gemini API enables Retrieval Augmented Generation ("RAG") through the File Search tool. File Search imports, chunks, and indexes your data to enable fast retrieval of relevant information based on a provided prompt. This retrieved information is then used as context for the model, allowing it to provide more accurate and relevant answers. File search is also able to provide multimodal capabilities with text embeddings supported by `gemini-embedding-001`, and image/multimodal embedding supported by `gemini-embedding-2`. {% callout type="note" %} Audio and video formats are not currently supported. {% /callout %} File storage and embedding generation at query time is free, and you'll only pay for creating embeddings when you first index your files and the normal Gemini model input / output tokens cost. This new billing paradigm makes the File Search Tool both easier and more cost-effective to build and scale with. See [pricing](/docs/file-search#pricing) section for details. ## Directly upload to File Search store {% id="upload" %} This example shows how to directly upload a file to the [file search store](https://ai.google.dev/api/file-search/file-search-stores#method:-media.uploadtofilesearchstore): {% tabs %} {% tab label="Python" %} ```python from google import genai from google.genai import types import time client = genai.Client() file_search_store = client.file_search_stores.create( config={ 'display_name': 'your-fileSearchStore-name', 'embedding_model': 'models/gemini-embedding-2' } ) operation = client.file_search_stores.upload_to_file_search_store( file='sample.txt', file_search_store_name=file_search_store.name, config={ 'display_name' : 'display-file-name', } ) while not operation.done: time.sleep(5) operation = client.operations.get(operation) interaction = client.interactions.create( model="gemini-3.8-flash", input="Can you tell me about [insert question]", tools=[{ "type": "file_search", "file_search_store_names": [file_search_store.name] }] ) for step in interaction.steps: if step.type == "model_output": for content_block in step.content: if content_block.type == "text": print(content_block.text) if content_block.annotations: print("\nSources:") for annotation in content_block.annotations: if annotation.type == "file_citation": print(f" - {annotation.file_name}: {annotation.source}") ``` {% /tab %} {% tab label="JavaScript" %} ```javascript const { GoogleGenAI } = require('@google/genai'); const ai = new GoogleGenAI({}); async function run() { const fileSearchStore = await ai.fileSearchStores.create({ config: { displayName: 'your-fileSearchStore-name', embeddingModel: 'models/gemini-embedding-2' } }); let operation = await ai.fileSearchStores.uploadToFileSearchStore({ file: 'file.txt', fileSearchStoreName: fileSearchStore.name, config: { displayName: 'file-name', } }); while (!operation.done) { await new Promise(resolve => setTimeout(resolve, 5000)); operation = await ai.operations.get({ operation }); } const interaction = await ai.interactions.create({ model: "gemini-3.8-flash", input: "Can you tell me about [insert question]", tools: [{ type: "file_search", file_search_store_names: [fileSearchStore.name] }] }); for (const step of interaction.steps) { if (step.type === 'model_output') { for (const contentBlock of step.content || []) { if (contentBlock.type === 'text') { console.log(contentBlock.text); if (contentBlock.annotations) { console.log("\nSources:"); for (const annotation of contentBlock.annotations) { if (annotation.type === 'file_citation') { console.log(` - ${annotation.file_name}: ${annotation.source}`); } } } } } } } } await run(); ``` {% /tab %} {% tab label="Java" %} ```java import com.google.genai.Client; import com.google.genai.gaos.models.interactions.Annotation; import com.google.genai.gaos.models.interactions.Content; import com.google.genai.gaos.models.interactions.CreateModelInteraction; import com.google.genai.gaos.models.interactions.FileCitation; import com.google.genai.gaos.models.interactions.FileSearch; import com.google.genai.gaos.models.interactions.Interaction; import com.google.genai.gaos.models.interactions.InteractionsInput; import com.google.genai.gaos.models.interactions.Model; import com.google.genai.gaos.models.interactions.ModelOutputStep; import com.google.genai.gaos.models.interactions.Step; import com.google.genai.gaos.models.interactions.TextContent; import com.google.genai.gaos.models.operations.CreateInteractionRequestBody; import com.google.genai.types.CreateFileSearchStoreConfig; import com.google.genai.types.FileSearchStore; import com.google.genai.types.UploadToFileSearchStoreConfig; import com.google.genai.types.UploadToFileSearchStoreOperation; import java.util.Arrays; Client client = new Client(); FileSearchStore fileSearchStore = client.fileSearchStores.create( CreateFileSearchStoreConfig.builder() .displayName("your-fileSearchStore-name") .embeddingModel("models/gemini-embedding-2") .build()); UploadToFileSearchStoreOperation operation = client.fileSearchStores.uploadToFileSearchStore( fileSearchStore.name().get(), "sample.txt", UploadToFileSearchStoreConfig.builder().displayName("display-file-name").build()); while (!operation.done().orElse(false)) { Thread.sleep(5000); operation = client.operations.get(operation, null); } CreateModelInteraction params = CreateModelInteraction.builder() .model(Model.of("gemini-3.8-flash")) .input(InteractionsInput.of("Can you tell me about [insert question]")) .tools( Arrays.asList( FileSearch.builder() .fileSearchStoreNames(Arrays.asList(fileSearchStore.name().get())) .build())) .build(); Interaction interaction = client.interactions.create(CreateInteractionRequestBody.of(params)).interaction().get(); if (interaction.steps().isPresent()) { for (Step step : interaction.steps().get()) { if (step instanceof ModelOutputStep) { ModelOutputStep outputStep = (ModelOutputStep) step; if (outputStep.content().isPresent()) { for (Content contentBlock : outputStep.content().get()) { if (contentBlock instanceof TextContent) { TextContent textContent = (TextContent) contentBlock; System.out.println(textContent.text().orElse("")); if (textContent.annotations().isPresent() && !textContent.annotations().get().isEmpty()) { System.out.println("\nSources:"); for (Annotation annotation : textContent.annotations().get()) { if (annotation instanceof FileCitation) { FileCitation citation = (FileCitation) annotation; System.out.printf( " - %s: %s%n", citation.fileName().orElse(""), citation.source().orElse("")); } } } } } } } } } ``` {% /tab %} {% tab label="Go" %} ```go package main import ( "context" "fmt" "log" "time" "google.golang.org/genai" "google.golang.org/genai/interactions/models/interactions" "google.golang.org/genai/interactions/models/operations" ) func main() { ctx := context.Background() client, err := genai.NewClient(ctx, nil) if err != nil { log.Fatal(err) } fileSearchStore, err := client.FileSearchStores.Create(ctx, &genai.CreateFileSearchStoreConfig{ DisplayName: "your-fileSearchStore-name", EmbeddingModel: "models/gemini-embedding-2", }) if err != nil { log.Fatal(err) } operation, err := client.FileSearchStores.UploadToFileSearchStoreFromPath( ctx, "sample.txt", fileSearchStore.Name, &genai.UploadToFileSearchStoreConfig{ DisplayName: "display-file-name", }, ) if err != nil { log.Fatal(err) } for !operation.Done { time.Sleep(5 * time.Second) operation, err = client.Operations.GetUploadToFileSearchStoreOperation(ctx, operation, nil) if err != nil { log.Fatal(err) } } resp, err := client.Interactions.Create(ctx, operations.CreateInteractionRequest{ Body: operations.NewCreateInteractionRequestBody( interactions.CreateModelInteraction{ Model: interactions.Model("gemini-3.8-flash"), Input: interactions.NewInteractionsInput("Can you tell me about [insert question]"), Tools: []interactions.Tool{ interactions.NewTool(interactions.FileSearch{ FileSearchStoreNames: []string{fileSearchStore.Name}, }), }, }, ), }) if err != nil { log.Fatal(err) } for _, step := range resp.Interaction.Steps { if step.ModelOutputStep != nil { for _, content := range step.ModelOutputStep.Content { if content.TextContent != nil { fmt.Println(content.TextContent.Text) if len(content.TextContent.Annotations) > 0 { fmt.Println("\nSources:") for _, annotation := range content.TextContent.Annotations { if annotation.FileCitation != nil { c := annotation.FileCitation fileName := "" if c.FileName != nil { fileName = *c.FileName } source := "" if c.Source != nil { source = *c.Source } fmt.Printf(" - %s: %s\n", fileName, source) } } } } } } } } ``` {% /tab %} {% /tabs %} Check the API reference for [`uploadToFileSearchStore`](https://ai.google.dev/api/file-search/file-search-stores#method:-media.uploadtofilesearchstore) for more information. ## Importing files {% id="importing-files" %} Alternatively, you can upload an existing file and [import it to your file search store](https://ai.google.dev/api/file-search/file-search-stores#method:-filesearchstores.importfile): {% tabs %} {% tab label="Python" %} ```python from google import genai from google.genai import types import time client = genai.Client() sample_file = client.files.upload(file='sample.txt', config={'display_name': 'display_file_name'}) file_search_store = client.file_search_stores.create( config={ 'display_name': 'your-fileSearchStore-name', 'embedding_model': 'models/gemini-embedding-2' } ) operation = client.file_search_stores.import_file( file_search_store_name=file_search_store.name, file_name=sample_file.name ) while not operation.done: time.sleep(5) operation = client.operations.get(operation) interaction = client.interactions.create( model="gemini-3.8-flash", input="Can you tell me about [insert question]", tools=[{ "type": "file_search", "file_search_store_names": [file_search_store.name] }] ) for step in interaction.steps: if step.type == "model_output": for content_block in step.content: if content_block.type == "text": print(content_block.text) ``` {% /tab %} {% tab label="JavaScript" %} ```javascript const { GoogleGenAI } = require('@google/genai'); const ai = new GoogleGenAI({}); async function run() { const sampleFile = await ai.files.upload({ file: 'sample.txt', config: { displayName: 'file-name' } }); const fileSearchStore = await ai.fileSearchStores.create({ config: { displayName: 'your-fileSearchStore-name', embeddingModel: 'models/gemini-embedding-2' } }); let operation = await ai.fileSearchStores.importFile({ fileSearchStoreName: fileSearchStore.name, fileName: sampleFile.name }); while (!operation.done) { await new Promise(resolve => setTimeout(resolve, 5000)); operation = await ai.operations.get({ operation: operation }); } const interaction = await ai.interactions.create({ model: "gemini-3.8-flash", input: "Can you tell me about [insert question]", tools: [{ type: "file_search", file_search_store_names: [fileSearchStore.name] }] }); for (const step of interaction.steps) { if (step.type === 'model_output') { for (const contentBlock of step.content || []) { if (contentBlock.type === 'text') { console.log(contentBlock.text); } } } } } await run(); ``` {% /tab %} {% tab label="Java" %} ```java import com.google.genai.Client; import com.google.genai.gaos.models.interactions.Content; import com.google.genai.gaos.models.interactions.CreateModelInteraction; import com.google.genai.gaos.models.interactions.FileSearch; import com.google.genai.gaos.models.interactions.Interaction; import com.google.genai.gaos.models.interactions.InteractionsInput; import com.google.genai.gaos.models.interactions.Model; import com.google.genai.gaos.models.interactions.ModelOutputStep; import com.google.genai.gaos.models.interactions.Step; import com.google.genai.gaos.models.interactions.TextContent; import com.google.genai.gaos.models.operations.CreateInteractionRequestBody; import com.google.genai.types.CreateFileSearchStoreConfig; import com.google.genai.types.File; import com.google.genai.types.FileSearchStore; import com.google.genai.types.ImportFileOperation; import com.google.genai.types.UploadFileConfig; import java.util.Arrays; Client client = new Client(); File sampleFile = client.files.upload( "sample.txt", UploadFileConfig.builder().displayName("display_file_name").build()); FileSearchStore fileSearchStore = client.fileSearchStores.create( CreateFileSearchStoreConfig.builder() .displayName("your-fileSearchStore-name") .embeddingModel("models/gemini-embedding-2") .build()); ImportFileOperation operation = client.fileSearchStores.importFile( fileSearchStore.name().get(), sampleFile.name().get(), null); while (!operation.done().orElse(false)) { Thread.sleep(5000); operation = client.operations.get(operation, null); } CreateModelInteraction params = CreateModelInteraction.builder() .model(Model.of("gemini-3.8-flash")) .input(InteractionsInput.of("Can you tell me about [insert question]")) .tools( Arrays.asList( FileSearch.builder() .fileSearchStoreNames(Arrays.asList(fileSearchStore.name().get())) .build())) .build(); Interaction interaction = client.interactions.create(CreateInteractionRequestBody.of(params)).interaction().get(); if (interaction.steps().isPresent()) { for (Step step : interaction.steps().get()) { if (step instanceof ModelOutputStep) { ModelOutputStep outputStep = (ModelOutputStep) step; if (outputStep.content().isPresent()) { for (Content contentBlock : outputStep.content().get()) { if (contentBlock instanceof TextContent) { TextContent textContent = (TextContent) contentBlock; System.out.println(textContent.text().orElse("")); } } } } } } ``` {% /tab %} {% tab label="Go" %} ```go package main import ( "context" "fmt" "log" "time" "google.golang.org/genai" "google.golang.org/genai/interactions/models/interactions" "google.golang.org/genai/interactions/models/operations" ) func main() { ctx := context.Background() client, err := genai.NewClient(ctx, nil) if err != nil { log.Fatal(err) } sampleFile, err := client.Files.UploadFromPath(ctx, "sample.txt", &genai.UploadFileConfig{ DisplayName: "display_file_name", }) if err != nil { log.Fatal(err) } fileSearchStore, err := client.FileSearchStores.Create(ctx, &genai.CreateFileSearchStoreConfig{ DisplayName: "your-fileSearchStore-name", EmbeddingModel: "models/gemini-embedding-2", }) if err != nil { log.Fatal(err) } operation, err := client.FileSearchStores.ImportFile(ctx, fileSearchStore.Name, sampleFile.Name, nil) if err != nil { log.Fatal(err) } for !operation.Done { time.Sleep(5 * time.Second) operation, err = client.Operations.GetImportFileOperation(ctx, operation, nil) if err != nil { log.Fatal(err) } } resp, err := client.Interactions.Create(ctx, operations.CreateInteractionRequest{ Body: operations.NewCreateInteractionRequestBody( interactions.CreateModelInteraction{ Model: interactions.Model("gemini-3.8-flash"), Input: interactions.NewInteractionsInput("Can you tell me about [insert question]"), Tools: []interactions.Tool{ interactions.NewTool(interactions.FileSearch{ FileSearchStoreNames: []string{fileSearchStore.Name}, }), }, }, ), }) if err != nil { log.Fatal(err) } for _, step := range resp.Interaction.Steps { if step.ModelOutputStep != nil { for _, content := range step.ModelOutputStep.Content { if content.TextContent != nil { fmt.Println(content.TextContent.Text) } } } } } ``` {% /tab %} {% /tabs %} Check the API reference for [`importFile`](https://ai.google.dev/api/file-search/file-search-stores#method:-filesearchstores.importfile) for more information. ## Chunking configuration {% id="chunking-configuration" %} When you import a file into a File Search store, it's automatically broken down into chunks, embedded, indexed, and uploaded to your File Search store. If you need more control over the chunking strategy, you can specify a [`chunking_config`](https://ai.google.dev/api/file-search/file-search-stores#request-body_5) setting to set a maximum number of tokens per chunk and maximum number of overlapping tokens. {% tabs %} {% tab label="Python" %} ```python from google import genai from google.genai import types import time client = genai.Client() operation = client.file_search_stores.upload_to_file_search_store( file_search_store_name=file_search_store.name, file='sample.txt', config={ 'chunking_config': { 'white_space_config': { 'max_tokens_per_chunk': 200, 'max_overlap_tokens': 20 } } } ) while not operation.done: time.sleep(5) operation = client.operations.get(operation) print("Custom chunking complete.") ``` {% /tab %} {% tab label="JavaScript" %} ```javascript const { GoogleGenAI } = require('@google/genai'); const ai = new GoogleGenAI({}); let operation = await ai.fileSearchStores.uploadToFileSearchStore({ file: 'file.txt', fileSearchStoreName: fileSearchStore.name, config: { displayName: 'file-name', chunkingConfig: { whiteSpaceConfig: { maxTokensPerChunk: 200, maxOverlapTokens: 20 } } } }); while (!operation.done) { await new Promise(resolve => setTimeout(resolve, 5000)); operation = await ai.operations.get({ operation }); } console.log("Custom chunking complete."); ``` {% /tab %} {% tab label="Java" %} ```java import com.google.genai.Client; import com.google.genai.types.ChunkingConfig; import com.google.genai.types.UploadToFileSearchStoreConfig; import com.google.genai.types.UploadToFileSearchStoreOperation; import com.google.genai.types.WhiteSpaceConfig; Client client = new Client(); UploadToFileSearchStoreOperation operation = client.fileSearchStores.uploadToFileSearchStore( "fileSearchStores/my-file-search-store", "sample.txt", UploadToFileSearchStoreConfig.builder() .displayName("file-name") .chunkingConfig( ChunkingConfig.builder() .whiteSpaceConfig( WhiteSpaceConfig.builder() .maxTokensPerChunk(200) .maxOverlapTokens(20) .build()) .build()) .build()); while (!operation.done().orElse(false)) { Thread.sleep(5000); operation = client.operations.get(operation, null); } System.out.println("Custom chunking complete."); ``` {% /tab %} {% tab label="Go" %} ```go package main import ( "context" "fmt" "log" "time" "google.golang.org/genai" ) func main() { ctx := context.Background() client, err := genai.NewClient(ctx, nil) if err != nil { log.Fatal(err) } operation, err := client.FileSearchStores.UploadToFileSearchStoreFromPath( ctx, "sample.txt", "fileSearchStores/my-file-search-store", &genai.UploadToFileSearchStoreConfig{ DisplayName: "file-name", ChunkingConfig: &genai.ChunkingConfig{ WhiteSpaceConfig: &genai.WhiteSpaceConfig{ MaxTokensPerChunk: genai.Ptr(int32(200)), MaxOverlapTokens: genai.Ptr(int32(20)), }, }, }, ) if err != nil { log.Fatal(err) } for !operation.Done { time.Sleep(5 * time.Second) operation, err = client.Operations.GetUploadToFileSearchStoreOperation(ctx, operation, nil) if err != nil { log.Fatal(err) } } fmt.Println("Custom chunking complete.") } ``` {% /tab %} {% /tabs %} To use your File Search store, pass it as a tool to the `interactions.create` method, as shown in the [Upload](/docs/file-search#upload) and [Import](/docs/file-search#importing-files) examples. ## How it works {% id="how-it-works" %} File Search uses a technique called semantic search to find information relevant to the user prompt. Unlike standard keyword-based search, semantic search understands the meaning and context of your query. When you import a file, it's converted into numerical representations called [embeddings](/docs/embeddings), which capture the semantic meaning of the uploaded content. These embeddings are stored in a specialized File Search database. When you make a query, it's also converted into an embedding. Then the system performs a File Search to find the most similar and relevant document chunks from the File Search store. There is no Time To Live (TTL) for embeddings; they persist until manually deleted, or when the model is deprecated. Files, however, are deleted after 48 hours. Here's a breakdown of the process for using the File Search `uploadToFileSearchStore` API: 1. **Create a File Search store**: A File Search store contains the processed data from your files. It's the persistent container for the embeddings that the semantic search will operate on. 2. **Upload a file and import into a File Search store**: Simultaneously upload a file and import the results into your File Search store. This creates a temporary `File` object, which is a reference to your raw document. That data is then chunked, converted into File Search embeddings, and indexed. The `File` object gets deleted after 48 hours, while the data imported into the File Search store will be stored indefinitely until you choose to delete it. 3. **Query with File Search**: Finally, you use the `FileSearch` tool in a `generateContent` call. In the tool configuration, you specify a `FileSearchRetrievalResource`, which points to the `FileSearchStore` you want to search. This tells the model to perform a semantic search on that specific File Search store to find relevant information to ground its response. ![](https://www.gstatic.com/cloud-cms/def39b91d11c6d080f235056ad4d90ee.png)In this diagram, the dotted line from *Documents* to *Embedding model* (using [`gemini-embedding-001`](/docs/embeddings)) represents the `uploadToFileSearchStore` API (bypassing *File storage*). Otherwise, using the [Files API](/docs/files) to separately create and then import files moves the indexing process from *Documents* to *File storage* and then to *Embedding model*. ## File Search stores {% id="file-search-stores" %} A File Search store is a container for your document embeddings. While raw files uploaded through the File API are deleted after 48 hours, the data imported into a File Search store is stored indefinitely until you manually delete it. You can create multiple File Search stores to organize your documents. The `FileSearchStore` API lets you create, list, get, and delete to manage your file search stores. File Search store names are globally scoped. Here are some examples of how to manage your File Search stores: {% tabs %} {% tab label="Python" %} ```python file_search_store = client.file_search_stores.create( config={ 'display_name': 'my-file_search-store-123', 'embedding_model': 'models/gemini-embedding-2' } ) for file_search_store in client.file_search_stores.list(): print(file_search_store) my_file_search_store = client.file_search_stores.get(name='fileSearchStores/my-file_search-store-123') client.file_search_stores.delete(name='fileSearchStores/my-file_search-store-123', config={'force': True}) ``` {% /tab %} {% tab label="JavaScript" %} ```javascript const fileSearchStore = await ai.fileSearchStores.create({ config: { displayName: 'my-file_search-store-123', embeddingModel: 'models/gemini-embedding-2' } }); const fileSearchStores = await ai.fileSearchStores.list(); for await (const store of fileSearchStores) { console.log(store); } const myFileSearchStore = await ai.fileSearchStores.get({ name: 'fileSearchStores/my-file_search-store-123' }); await ai.fileSearchStores.delete({ name: 'fileSearchStores/my-file_search-store-123', config: { force: true } }); ``` {% /tab %} {% tab label="Java" %} ```java import com.google.genai.Client; import com.google.genai.types.CreateFileSearchStoreConfig; import com.google.genai.types.DeleteFileSearchStoreConfig; import com.google.genai.types.FileSearchStore; Client client = new Client(); FileSearchStore fileSearchStore = client.fileSearchStores.create( CreateFileSearchStoreConfig.builder() .displayName("myfilesearchstore123") .embeddingModel("models/gemini-embedding-2") .build()); for (FileSearchStore store : client.fileSearchStores.list(null)) { System.out.println(store); } FileSearchStore myFileSearchStore = client.fileSearchStores.get(fileSearchStore.name().get(), null); client.fileSearchStores.delete( fileSearchStore.name().get(), DeleteFileSearchStoreConfig.builder().force(true).build()); ``` {% /tab %} {% tab label="Go" %} ```go package main import ( "context" "fmt" "log" "google.golang.org/genai" ) func main() { ctx := context.Background() client, err := genai.NewClient(ctx, nil) if err != nil { log.Fatal(err) } fileSearchStore, err := client.FileSearchStores.Create(ctx, &genai.CreateFileSearchStoreConfig{ DisplayName: "myfilesearchstore123", EmbeddingModel: "models/gemini-embedding-2", }) if err != nil { log.Fatal(err) } for store, err := range client.FileSearchStores.All(ctx) { if err != nil { log.Fatal(err) } fmt.Println(store) } myFileSearchStore, err := client.FileSearchStores.Get(ctx, fileSearchStore.Name, nil) if err != nil { log.Fatal(err) } _ = myFileSearchStore err = client.FileSearchStores.Delete(ctx, fileSearchStore.Name, &genai.DeleteFileSearchStoreConfig{ Force: genai.Ptr(true), }) if err != nil { log.Fatal(err) } } ``` {% /tab %} {% tab label="REST" %} ```shell curl -X POST "https://generativelanguage.googleapis.com/v1beta/fileSearchStores?key=${GEMINI_API_KEY}" \ -H "Content-Type: application/json" \ -d '{ "displayName": "My Store", "embedding_model": "models/gemini-embedding-2" }' curl "https://generativelanguage.googleapis.com/v1beta/fileSearchStores?key=${GEMINI_API_KEY}" \ curl "https://generativelanguage.googleapis.com/v1beta/fileSearchStores/my-file_search-store-123?key=${GEMINI_API_KEY}" curl -X DELETE "https://generativelanguage.googleapis.com/v1beta/fileSearchStores/my-file_search-store-123?key=${GEMINI_API_KEY}" ``` {% /tab %} {% /tabs %} ## File Search documents {% id="file-search-documents" %} You can manage individual documents in your file stores with the [File Search Documents](https://ai.google.dev/api/file-search/documents) API to `list` each document in a file search store, `get` information about a document, and `delete` a document by name. {% tabs %} {% tab label="Python" %} ```python for document_in_store in client.file_search_stores.documents.list(parent='fileSearchStores/my-file_search-store-123'): print(document_in_store) file_search_document = client.file_search_stores.documents.get(name='fileSearchStores/my-file_search-store-123/documents/my_doc') print(file_search_document) client.file_search_stores.documents.delete(name='fileSearchStores/my-file_search-store-123/documents/my_doc', config={'force': True}) ``` {% /tab %} {% tab label="JavaScript" %} ```javascript const documents = await ai.fileSearchStores.documents.list({ parent: 'fileSearchStores/my-file_search-store-123' }); for await (const doc of documents) { console.log(doc); } const fileSearchDocument = await ai.fileSearchStores.documents.get({ name: 'fileSearchStores/my-file_search-store-123/documents/my_doc' }); await ai.fileSearchStores.documents.delete({ name: 'fileSearchStores/my-file_search-store-123/documents/my_doc' }); ``` {% /tab %} {% tab label="Java" %} ```java import com.google.genai.Client; import com.google.genai.types.DeleteDocumentConfig; import com.google.genai.types.Document; Client client = new Client(); for (Document documentInStore : client.fileSearchStores.documents.list("fileSearchStores/myfilesearchstore123", null)) { System.out.println(documentInStore); } Document fileSearchDocument = client.fileSearchStores.documents.get( "fileSearchStores/myfilesearchstore123/documents/sampletxt123", null); System.out.println(fileSearchDocument); client.fileSearchStores.documents.delete( "fileSearchStores/myfilesearchstore123/documents/sampletxt123", DeleteDocumentConfig.builder().force(true).build()); ``` {% /tab %} {% tab label="Go" %} ```go package main import ( "context" "fmt" "log" "google.golang.org/genai" ) func main() { ctx := context.Background() client, err := genai.NewClient(ctx, nil) if err != nil { log.Fatal(err) } for documentInStore, err := range client.FileSearchStores.Documents.All(ctx, "fileSearchStores/myfilesearchstore123") { if err != nil { log.Fatal(err) } fmt.Println(documentInStore) } fileSearchDocument, err := client.FileSearchStores.Documents.Get(ctx, "fileSearchStores/myfilesearchstore123/documents/sampletxt123", nil) if err != nil { log.Fatal(err) } fmt.Println(fileSearchDocument) err = client.FileSearchStores.Documents.Delete(ctx, "fileSearchStores/myfilesearchstore123/documents/sampletxt123", &genai.DeleteDocumentConfig{ Force: genai.Ptr(true), }) if err != nil { log.Fatal(err) } } ``` {% /tab %} {% tab label="REST" %} ```shell curl "https://generativelanguage.googleapis.com/v1beta/fileSearchStores/my-file_search-store-123/documents?key=${GEMINI_API_KEY}" curl "https://generativelanguage.googleapis.com/v1beta/fileSearchStores/my-file_search-store-123/documents/my_doc?key=${GEMINI_API_KEY}" curl -X DELETE "https://generativelanguage.googleapis.com/v1beta/fileSearchStores/my-file_search-store-123/documents/my_doc?key=${GEMINI_API_KEY}&force=true" ``` {% /tab %} {% /tabs %} ## File metadata {% id="metadata" %} You can add custom metadata to your files to help filter them or provide additional context. Metadata is a set of key-value pairs. {% tabs %} {% tab label="Python" %} ```python op = client.file_search_stores.import_file( file_search_store_name=file_search_store.name, file_name=sample_file.name, config={ 'custom_metadata': [ {"key": "author", "string_value": "Robert Graves"}, {"key": "year", "numeric_value": 1934} ] } ) ``` {% /tab %} {% tab label="JavaScript" %} ```javascript let operation = await ai.fileSearchStores.importFile({ fileSearchStoreName: fileSearchStore.name, fileName: sampleFile.name, config: { customMetadata: [ { key: "author", stringValue: "Robert Graves" }, { key: "year", numericValue: 1934 } ] } }); ``` {% /tab %} {% tab label="Java" %} ```java import com.google.genai.Client; import com.google.genai.types.CustomMetadata; import com.google.genai.types.ImportFileConfig; import com.google.genai.types.ImportFileOperation; import java.util.Arrays; Client client = new Client(); ImportFileOperation op = client.fileSearchStores.importFile( "fileSearchStores/myfilesearchstore123", "files/samplefile123", ImportFileConfig.builder() .customMetadata( Arrays.asList( CustomMetadata.builder().key("author").stringValue("Robert Graves").build(), CustomMetadata.builder().key("year").numericValue(1934f).build())) .build()); ``` {% /tab %} {% tab label="Go" %} ```go package main import ( "context" "log" "google.golang.org/genai" ) func main() { ctx := context.Background() client, err := genai.NewClient(ctx, nil) if err != nil { log.Fatal(err) } op, err := client.FileSearchStores.ImportFile( ctx, "fileSearchStores/myfilesearchstore123", "files/samplefile123", &genai.ImportFileConfig{ CustomMetadata: []*genai.CustomMetadata{ {Key: "author", StringValue: "Robert Graves"}, {Key: "year", NumericValue: genai.Ptr(float32(1934))}, }, }, ) if err != nil { log.Fatal(err) } _ = op } ``` {% /tab %} {% /tabs %} This is useful when you have multiple documents in a File Search store and want to search only a subset of them. {% tabs %} {% tab label="Python" %} ```python interaction = client.interactions.create( model="gemini-3.8-flash", input="Tell me about the book 'I, Claudius'", tools=[{ "type": "file_search", "file_search_store_names": [file_search_store.name], "metadata_filter": 'author="Robert Graves"', }] ) for step in interaction.steps: if step.type == "model_output": for content_block in step.content: if content_block.type == "text": print(content_block.text) ``` {% /tab %} {% tab label="JavaScript" %} ```javascript const interaction = await ai.interactions.create({ model: "gemini-3.8-flash", input: "Tell me about the book 'I, Claudius'", tools: [{ type: "file_search", file_search_store_names: [fileSearchStore.name], metadata_filter: 'author="Robert Graves"', }] }); for (const step of interaction.steps) { if (step.type === 'model_output') { for (const contentBlock of step.content || []) { if (contentBlock.type === 'text') { console.log(contentBlock.text); } } } } ``` {% /tab %} {% tab label="Java" %} ```java import com.google.genai.Client; import com.google.genai.gaos.models.interactions.Content; import com.google.genai.gaos.models.interactions.CreateModelInteraction; import com.google.genai.gaos.models.interactions.FileSearch; import com.google.genai.gaos.models.interactions.Interaction; import com.google.genai.gaos.models.interactions.InteractionsInput; import com.google.genai.gaos.models.interactions.Model; import com.google.genai.gaos.models.interactions.ModelOutputStep; import com.google.genai.gaos.models.interactions.Step; import com.google.genai.gaos.models.interactions.TextContent; import com.google.genai.gaos.models.operations.CreateInteractionRequestBody; import java.util.Arrays; Client client = new Client(); CreateModelInteraction params = CreateModelInteraction.builder() .model(Model.of("gemini-3.8-flash")) .input(InteractionsInput.of("Tell me about the book 'I, Claudius'")) .tools( Arrays.asList( FileSearch.builder() .fileSearchStoreNames(Arrays.asList("fileSearchStores/myfilesearchstore123")) .metadataFilter("author=\"Robert Graves\"") .build())) .build(); Interaction interaction = client.interactions.create(CreateInteractionRequestBody.of(params)).interaction().get(); if (interaction.steps().isPresent()) { for (Step step : interaction.steps().get()) { if (step instanceof ModelOutputStep) { ModelOutputStep outputStep = (ModelOutputStep) step; if (outputStep.content().isPresent()) { for (Content contentBlock : outputStep.content().get()) { if (contentBlock instanceof TextContent) { TextContent textContent = (TextContent) contentBlock; System.out.println(textContent.text().orElse("")); } } } } } } ``` {% /tab %} {% tab label="Go" %} ```go package main import ( "context" "fmt" "log" "google.golang.org/genai" "google.golang.org/genai/interactions/models/interactions" "google.golang.org/genai/interactions/models/operations" ) func main() { ctx := context.Background() client, err := genai.NewClient(ctx, nil) if err != nil { log.Fatal(err) } resp, err := client.Interactions.Create(ctx, operations.CreateInteractionRequest{ Body: operations.NewCreateInteractionRequestBody( interactions.CreateModelInteraction{ Model: interactions.Model("gemini-3.8-flash"), Input: interactions.NewInteractionsInput("Tell me about the book 'I, Claudius'"), Tools: []interactions.Tool{ interactions.NewTool(interactions.FileSearch{ FileSearchStoreNames: []string{"fileSearchStores/myfilesearchstore123"}, MetadataFilter: genai.Ptr(`author="Robert Graves"`), }), }, }, ), }) if err != nil { log.Fatal(err) } for _, step := range resp.Interaction.Steps { if step.ModelOutputStep != nil { for _, content := range step.ModelOutputStep.Content { if content.TextContent != nil { fmt.Println(content.TextContent.Text) } } } } } ``` {% /tab %} {% tab label="REST" %} ```shell curl "https://generativelanguage.googleapis.com/v1beta/interactions" \ -H "x-goog-api-key: $GEMINI_API_KEY" \ -H 'Content-Type: application/json' \ -H "Api-Revision: 2026-05-20" \ -X POST \ -d '{ "model": "gemini-3.8-flash", "input": [{"type": "text", "text": "Tell me about the book I, Claudius"}], "tools": [{ "type": "file_search", "file_search_store_names": ["'$STORE_NAME'"], "metadata_filter": "author = \"Robert Graves\"" }] }' 2> /dev/null > response.json cat response.json ``` {% /tab %} {% /tabs %} Guidance on implementing list filter syntax for `metadata_filter` can be found at [google.aip.dev/160](https://google.aip.dev/160) ## Multimodal File Search {% id="multimodal-file-search" %} Multimodal File Search lets you to natively embed and search through images, enabling rich, multimodal RAG applications. ### Configure the embedding model {% id="configure-the-embedding-model" %} When you create a `FileSearchStore`, you must override the default text-only embedding model to use a multimodal model. Use `models/gemini-embedding-2` to process both text and images. {% tabs %} {% tab label="Python" %} ```python store = client.file_search_stores.create( config={ "display_name": "Multimodal Catalog", "embedding_model": "models/gemini-embedding-2", } ) ``` {% /tab %} {% tab label="JavaScript" %} ```javascript const fileSearchStore = await ai.fileSearchStores.create({ config: { displayName: "Multimodal Catalog", embeddingModel: "models/gemini-embedding-2", }, }); ``` {% /tab %} {% tab label="Java" %} ```java import com.google.genai.Client; import com.google.genai.types.CreateFileSearchStoreConfig; import com.google.genai.types.FileSearchStore; Client client = new Client(); FileSearchStore store = client.fileSearchStores.create( CreateFileSearchStoreConfig.builder() .displayName("Multimodal Catalog") .embeddingModel("models/gemini-embedding-2") .build()); ``` {% /tab %} {% tab label="Go" %} ```go package main import ( "context" "log" "google.golang.org/genai" ) func main() { ctx := context.Background() client, err := genai.NewClient(ctx, nil) if err != nil { log.Fatal(err) } store, err := client.FileSearchStores.Create(ctx, &genai.CreateFileSearchStoreConfig{ DisplayName: "Multimodal Catalog", EmbeddingModel: "models/gemini-embedding-2", }) if err != nil { log.Fatal(err) } _ = store } ``` {% /tab %} {% tab label="REST" %} ```bash curl -X POST "https://generativelanguage.googleapis.com/v1beta/fileSearchStores?key=$GEMINI_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "display_name": "Multimodal Catalog", "embedding_model": "models/gemini-embedding-2" }' ``` {% /tab %} {% /tabs %} ### Upload images {% id="upload-images" %} After you create the store with a multimodal embedding model, you can upload image files directly using the same upload APIs described in [Directly upload to File Search store](/docs/file-search#upload) or [Importing files](/docs/file-search#importing-files). **Image file requirements:** - Image files must be at most 4K x 4K pixels in resolution. - Supported formats are PNG, JPEG. ## Citations {% id="citations" %} When you use File Search, the model's response may include citations that specify which parts of your uploaded documents were used to generate the answer. This helps with fact-checking and verification. You can access citation information through the `annotations` attribute inside the `model_output` step's `content` blocks of the response. {% tabs %} {% tab label="Python" %} ```python for step in interaction.steps: if step.type == 'model_output': for content in step.content: if content.type == 'text' and content.annotations: print(content.annotations) ``` {% /tab %} {% tab label="JavaScript" %} ```javascript for (const step of interaction.steps) { if (step.type === 'model_output') { for (const contentBlock of step.content || []) { if (contentBlock.type === 'text' && contentBlock.annotations) { console.log(JSON.stringify(contentBlock.annotations, null, 2)); } } } } ``` {% /tab %} {% tab label="Java" %} ```java import com.google.genai.Client; import com.google.genai.gaos.models.interactions.Content; import com.google.genai.gaos.models.interactions.CreateModelInteraction; import com.google.genai.gaos.models.interactions.FileSearch; import com.google.genai.gaos.models.interactions.Interaction; import com.google.genai.gaos.models.interactions.InteractionsInput; import com.google.genai.gaos.models.interactions.Model; import com.google.genai.gaos.models.interactions.ModelOutputStep; import com.google.genai.gaos.models.interactions.Step; import com.google.genai.gaos.models.interactions.TextContent; import com.google.genai.gaos.models.operations.CreateInteractionRequestBody; import java.util.Arrays; Client client = new Client(); CreateModelInteraction params = CreateModelInteraction.builder() .model(Model.of("gemini-3.8-flash")) .input(InteractionsInput.of("Can you tell me about [insert question]")) .tools( Arrays.asList( FileSearch.builder() .fileSearchStoreNames(Arrays.asList("fileSearchStores/myfilesearchstore123")) .build())) .build(); Interaction interaction = client.interactions.create(CreateInteractionRequestBody.of(params)).interaction().get(); if (interaction.steps().isPresent()) { for (Step step : interaction.steps().get()) { if (step instanceof ModelOutputStep) { ModelOutputStep outputStep = (ModelOutputStep) step; if (outputStep.content().isPresent()) { for (Content content : outputStep.content().get()) { if (content instanceof TextContent) { TextContent textContent = (TextContent) content; if (textContent.annotations().isPresent()) { System.out.println(textContent.annotations().get()); } } } } } } } ``` {% /tab %} {% tab label="Go" %} ```go package main import ( "context" "fmt" "log" "google.golang.org/genai" "google.golang.org/genai/interactions/models/interactions" "google.golang.org/genai/interactions/models/operations" ) func main() { ctx := context.Background() client, err := genai.NewClient(ctx, nil) if err != nil { log.Fatal(err) } resp, err := client.Interactions.Create(ctx, operations.CreateInteractionRequest{ Body: operations.NewCreateInteractionRequestBody( interactions.CreateModelInteraction{ Model: interactions.Model("gemini-3.8-flash"), Input: interactions.NewInteractionsInput("Can you tell me about [insert question]"), Tools: []interactions.Tool{ interactions.NewTool(interactions.FileSearch{ FileSearchStoreNames: []string{"fileSearchStores/myfilesearchstore123"}, }), }, }, ), }) if err != nil { log.Fatal(err) } for _, step := range resp.Interaction.Steps { if step.ModelOutputStep != nil { for _, content := range step.ModelOutputStep.Content { if content.TextContent != nil && len(content.TextContent.Annotations) > 0 { fmt.Println(content.TextContent.Annotations) } } } } } ``` {% /tab %} {% /tabs %} For detailed information on the structure of the citations, see the [API reference for Interactions](https://ai.google.dev/api/interactions-api#Resource:FileCitation). ### Page numbers {% id="page-numbers" %} When you use File Search with documents that have pages (such as PDFs), the model's response may include the page number where the information was found. You can access this information through the `page_number` attribute of a `file_citation` annotation. {% tabs %} {% tab label="Python" %} ```python for step in interaction.steps: if step.type == "model_output": for content in step.content: if content.type == "text" and content.annotations: for annotation in content.annotations: if annotation.type == "file_citation" and annotation.page_number: print(f"Cited Page: {annotation.page_number}") ``` {% /tab %} {% tab label="JavaScript" %} ```javascript for (const step of interaction.steps) { if (step.type === 'model_output') { for (const block of step.content || []) { if (block.type === 'text' && block.annotations) { for (const annotation of block.annotations) { if (annotation.type === 'file_citation' && annotation.page_number) { console.log(`Cited Page: ${annotation.page_number}`); } } } } } } ``` {% /tab %} {% tab label="Java" %} ```java import com.google.genai.Client; import com.google.genai.gaos.models.interactions.Annotation; import com.google.genai.gaos.models.interactions.Content; import com.google.genai.gaos.models.interactions.CreateModelInteraction; import com.google.genai.gaos.models.interactions.FileCitation; import com.google.genai.gaos.models.interactions.FileSearch; import com.google.genai.gaos.models.interactions.Interaction; import com.google.genai.gaos.models.interactions.InteractionsInput; import com.google.genai.gaos.models.interactions.Model; import com.google.genai.gaos.models.interactions.ModelOutputStep; import com.google.genai.gaos.models.interactions.Step; import com.google.genai.gaos.models.interactions.TextContent; import com.google.genai.gaos.models.operations.CreateInteractionRequestBody; import java.util.Arrays; Client client = new Client(); CreateModelInteraction params = CreateModelInteraction.builder() .model(Model.of("gemini-3.8-flash")) .input(InteractionsInput.of("Can you tell me about [insert question]")) .tools( Arrays.asList( FileSearch.builder() .fileSearchStoreNames(Arrays.asList("fileSearchStores/myfilesearchstore123")) .build())) .build(); Interaction interaction = client.interactions.create(CreateInteractionRequestBody.of(params)).interaction().get(); if (interaction.steps().isPresent()) { for (Step step : interaction.steps().get()) { if (step instanceof ModelOutputStep) { ModelOutputStep outputStep = (ModelOutputStep) step; if (outputStep.content().isPresent()) { for (Content content : outputStep.content().get()) { if (content instanceof TextContent) { TextContent textContent = (TextContent) content; if (textContent.annotations().isPresent()) { for (Annotation annotation : textContent.annotations().get()) { if (annotation instanceof FileCitation) { FileCitation citation = (FileCitation) annotation; if (citation.pageNumber().isPresent()) { System.out.println("Cited Page: " + citation.pageNumber().get()); } } } } } } } } } } ``` {% /tab %} {% tab label="Go" %} ```go package main import ( "context" "fmt" "log" "google.golang.org/genai" "google.golang.org/genai/interactions/models/interactions" "google.golang.org/genai/interactions/models/operations" ) func main() { ctx := context.Background() client, err := genai.NewClient(ctx, nil) if err != nil { log.Fatal(err) } resp, err := client.Interactions.Create(ctx, operations.CreateInteractionRequest{ Body: operations.NewCreateInteractionRequestBody( interactions.CreateModelInteraction{ Model: interactions.Model("gemini-3.8-flash"), Input: interactions.NewInteractionsInput("Can you tell me about [insert question]"), Tools: []interactions.Tool{ interactions.NewTool(interactions.FileSearch{ FileSearchStoreNames: []string{"fileSearchStores/myfilesearchstore123"}, }), }, }, ), }) if err != nil { log.Fatal(err) } for _, step := range resp.Interaction.Steps { if step.ModelOutputStep != nil { for _, content := range step.ModelOutputStep.Content { if content.TextContent != nil { for _, annotation := range content.TextContent.Annotations { if annotation.FileCitation != nil && annotation.FileCitation.PageNumber != nil { fmt.Println("Cited Page:", *annotation.FileCitation.PageNumber) } } } } } } } ``` {% /tab %} {% /tabs %} ### Media citations {% id="media-citations" %} When the model references an image chunk during generation, the API returns an annotation of type `file_citation` in the annotations that includes a `media_id`. You can use this ID to download the exact image chunk the model referenced. This `media_id` is persistent across multiple search calls, which lets you reliably retrieve the same image or cache it using the ID. The following snippet is an example REST response step: ```json { "type": "model_output", "content": [ { "type": "text", "text": "...", "annotations": [ { "type": "file_citation", "file_name": "product_image", "media_id": "fileSearchStores/my-store-123/media/BlobId-456" } ] } ] } ``` The following code snippets demonstrate how to retrieve the `media_id` and download the media: {% tabs %} {% tab label="Python" %} ```python for step in interaction.steps: if step.type == "model_output": for content in step.content: if content.type == "text" and content.annotations: for annotation in content.annotations: if annotation.type == "file_citation" and annotation.media_id: print(f"Cited Media ID: {annotation.media_id}") blob_content = client.file_search_stores.download_media( media_id=annotation.media_id ) ``` {% /tab %} {% tab label="JavaScript" %} ```javascript for (const step of interaction.steps) { if (step.type === 'model_output') { for (const block of step.content || []) { if (block.type === 'text' && block.annotations) { for (const annotation of block.annotations) { if (annotation.type === 'file_citation' && annotation.media_id) { console.log(`Cited Media ID: ${annotation.media_id}`); const blobContent = await ai.fileSearchStores.downloadMedia(annotation.media_id); } } } } } } ``` {% /tab %} {% tab label="Java" %} ```java import com.google.genai.Client; import com.google.genai.gaos.models.interactions.Annotation; import com.google.genai.gaos.models.interactions.Content; import com.google.genai.gaos.models.interactions.CreateModelInteraction; import com.google.genai.gaos.models.interactions.FileCitation; import com.google.genai.gaos.models.interactions.FileSearch; import com.google.genai.gaos.models.interactions.Interaction; import com.google.genai.gaos.models.interactions.InteractionsInput; import com.google.genai.gaos.models.interactions.Model; import com.google.genai.gaos.models.interactions.ModelOutputStep; import com.google.genai.gaos.models.interactions.Step; import com.google.genai.gaos.models.interactions.TextContent; import com.google.genai.gaos.models.operations.CreateInteractionRequestBody; import java.util.Arrays; Client client = new Client(); CreateModelInteraction params = CreateModelInteraction.builder() .model(Model.of("gemini-3.8-flash")) .input(InteractionsInput.of("Can you tell me about [insert question]")) .tools( Arrays.asList( FileSearch.builder() .fileSearchStoreNames(Arrays.asList("fileSearchStores/myfilesearchstore123")) .build())) .build(); Interaction interaction = client.interactions.create(CreateInteractionRequestBody.of(params)).interaction().get(); if (interaction.steps().isPresent()) { for (Step step : interaction.steps().get()) { if (step instanceof ModelOutputStep) { ModelOutputStep outputStep = (ModelOutputStep) step; if (outputStep.content().isPresent()) { for (Content content : outputStep.content().get()) { if (content instanceof TextContent) { TextContent textContent = (TextContent) content; if (textContent.annotations().isPresent()) { for (Annotation annotation : textContent.annotations().get()) { if (annotation instanceof FileCitation) { FileCitation citation = (FileCitation) annotation; if (citation.mediaId().isPresent()) { System.out.println("Cited Media ID: " + citation.mediaId().get()); byte[] blobContent = client.fileSearchStores.downloadMedia(citation.mediaId().get(), null); } } } } } } } } } } ``` {% /tab %} {% tab label="Go" %} ```go package main import ( "context" "fmt" "log" "google.golang.org/genai" "google.golang.org/genai/interactions/models/interactions" "google.golang.org/genai/interactions/models/operations" ) func main() { ctx := context.Background() client, err := genai.NewClient(ctx, nil) if err != nil { log.Fatal(err) } resp, err := client.Interactions.Create(ctx, operations.CreateInteractionRequest{ Body: operations.NewCreateInteractionRequestBody( interactions.CreateModelInteraction{ Model: interactions.Model("gemini-3.8-flash"), Input: interactions.NewInteractionsInput("Can you tell me about [insert question]"), Tools: []interactions.Tool{ interactions.NewTool(interactions.FileSearch{ FileSearchStoreNames: []string{"fileSearchStores/myfilesearchstore123"}, }), }, }, ), }) if err != nil { log.Fatal(err) } for _, step := range resp.Interaction.Steps { if step.ModelOutputStep != nil { for _, content := range step.ModelOutputStep.Content { if content.TextContent != nil { for _, annotation := range content.TextContent.Annotations { if annotation.FileCitation != nil && annotation.FileCitation.MediaID != nil { fmt.Println("Cited Media ID:", *annotation.FileCitation.MediaID) blobContent, err := client.FileSearchStores.DownloadMedia(ctx, *annotation.FileCitation.MediaID, nil) if err != nil { log.Fatal(err) } _ = blobContent } } } } } } } ``` {% /tab %} {% tab label="REST" %} ```bash curl -X GET "https://generativelanguage.googleapis.com/v1beta/fileSearchStores/my-store-123/media/BlobId-456?alt=media" \ -H "x-goog-api-key: $GEMINI_API_KEY" \ -o cited_image.png ``` {% /tab %} {% /tabs %} ## Custom metadata {% id="custom-metadata-grounding" %} If you have added custom metadata to your files, you can access it in the annotations of the model's response. This is useful for passing additional context (like URLs, page numbers, or authors) from your source documents to your application logic. Each citation annotation of type `file_citation` contains this custom metadata. {% tabs %} {% tab label="Python" %} ```python interaction = client.interactions.create( model="gemini-3.8-flash", input="Tell me about [insert question]", tools=[{ "type": "file_search", "file_search_store_names": [file_search_store.name] }] ) for step in interaction.steps: if step.type == "model_output": for content_block in step.content: if content_block.annotations: for annotation in content_block.annotations: print(annotation) ``` {% /tab %} {% tab label="JavaScript" %} ```javascript const interaction = await ai.interactions.create({ model: "gemini-3.8-flash", input: "Tell me about [insert question]", tools: [{ type: "file_search", file_search_store_names: [fileSearchStore.name] }] }); for (const step of interaction.steps) { if (step.type === 'model_output') { for (const contentBlock of step.content || []) { if (contentBlock.annotations) { contentBlock.annotations.forEach((annotation) => { console.log(annotation); }); } } } } ``` {% /tab %} {% tab label="Java" %} ```java import com.google.genai.Client; import com.google.genai.gaos.models.interactions.Annotation; import com.google.genai.gaos.models.interactions.Content; import com.google.genai.gaos.models.interactions.CreateModelInteraction; import com.google.genai.gaos.models.interactions.FileSearch; import com.google.genai.gaos.models.interactions.Interaction; import com.google.genai.gaos.models.interactions.InteractionsInput; import com.google.genai.gaos.models.interactions.Model; import com.google.genai.gaos.models.interactions.ModelOutputStep; import com.google.genai.gaos.models.interactions.Step; import com.google.genai.gaos.models.interactions.TextContent; import com.google.genai.gaos.models.operations.CreateInteractionRequestBody; import java.util.Arrays; Client client = new Client(); CreateModelInteraction params = CreateModelInteraction.builder() .model(Model.of("gemini-3.8-flash")) .input(InteractionsInput.of("Tell me about [insert question]")) .tools( Arrays.asList( FileSearch.builder() .fileSearchStoreNames(Arrays.asList("fileSearchStores/myfilesearchstore123")) .build())) .build(); Interaction interaction = client.interactions.create(CreateInteractionRequestBody.of(params)).interaction().get(); if (interaction.steps().isPresent()) { for (Step step : interaction.steps().get()) { if (step instanceof ModelOutputStep) { ModelOutputStep outputStep = (ModelOutputStep) step; if (outputStep.content().isPresent()) { for (Content contentBlock : outputStep.content().get()) { if (contentBlock instanceof TextContent) { TextContent textContent = (TextContent) contentBlock; if (textContent.annotations().isPresent()) { for (Annotation annotation : textContent.annotations().get()) { System.out.println(annotation); } } } } } } } } ``` {% /tab %} {% tab label="Go" %} ```go package main import ( "context" "fmt" "log" "google.golang.org/genai" "google.golang.org/genai/interactions/models/interactions" "google.golang.org/genai/interactions/models/operations" ) func main() { ctx := context.Background() client, err := genai.NewClient(ctx, nil) if err != nil { log.Fatal(err) } resp, err := client.Interactions.Create(ctx, operations.CreateInteractionRequest{ Body: operations.NewCreateInteractionRequestBody( interactions.CreateModelInteraction{ Model: interactions.Model("gemini-3.8-flash"), Input: interactions.NewInteractionsInput("Tell me about [insert question]"), Tools: []interactions.Tool{ interactions.NewTool(interactions.FileSearch{ FileSearchStoreNames: []string{"fileSearchStores/myfilesearchstore123"}, }), }, }, ), }) if err != nil { log.Fatal(err) } for _, step := range resp.Interaction.Steps { if step.ModelOutputStep != nil { for _, content := range step.ModelOutputStep.Content { if content.TextContent != nil { for _, annotation := range content.TextContent.Annotations { fmt.Println(annotation) } } } } } } ``` {% /tab %} {% tab label="REST" %} ```bash curl "https://generativelanguage.googleapis.com/v1beta/interactions" \ -H "x-goog-api-key: $GEMINI_API_KEY" \ -H "Content-Type: application/json" \ -H "Api-Revision: 2026-05-20" \ -X POST \ -d '{ "model": "gemini-3.8-flash", "input": "Tell me about [insert question]", "tools": [{ "type": "file_search", "file_search_store_names": ["'$FILE_SEARCH_STORE_NAME'"] }] }' ``` The custom metadata is returned in `custom_metadata` on each `file_citation` annotation: ```json { "steps": [ { "type": "model_output", "content": [ { "type": "text", "text": "...", "annotations": [ { "type": "file_citation", "file_name": "...", "document_uri": "...", "source": "...", "custom_metadata": { "author": "Robert Graves", "year": 1934 } } ] } ] } ] } ``` {% /tab %} {% /tabs %} ## Structured output {% id="structured-output" %} Starting with Gemini 3 models, you can combine file search tool with [structured outputs](/docs/structured-output). {% tabs %} {% tab label="Python" %} ```python from pydantic import BaseModel, Field class Money(BaseModel): amount: str = Field(description="The numerical part of the amount.") currency: str = Field(description="The currency of amount.") interaction = client.interactions.create( model="gemini-3.8-flash", input="What is the minimum hourly wage in Tokyo right now?", tools=[{ "type": "file_search", "file_search_store_names": [file_search_store.name] }], response_format={ "type": "text", "mime_type": "application/json", "schema": Money.model_json_schema() }, ) result = Money.model_validate_json(interaction.output_text) print(result) ``` {% /tab %} {% tab label="JavaScript" %} ```javascript import { z } from "zod"; const moneyJsonSchema = { type: "object", properties: { amount: { type: "string", description: "The numerical part of the amount." }, currency: { type: "string", description: "The currency of amount." } }, required: ["amount", "currency"] }; const moneySchema = z.fromJSONSchema(moneyJsonSchema); async function run() { const interaction = await ai.interactions.create({ model: "gemini-3.8-flash", input: "What is the minimum hourly wage in Tokyo right now?", tools: [{ type: "file_search", file_search_store_names: [fileSearchStore.name], }], response_format: { type: 'text', mime_type: 'application/json', schema: moneyJsonSchema }, }); const result = moneySchema.parse(JSON.parse(interaction.output_text)); console.log(result); } await run(); ``` {% /tab %} {% tab label="Java" %} ```java import com.google.genai.Client; import com.google.genai.gaos.models.interactions.CreateModelInteraction; import com.google.genai.gaos.models.interactions.CreateModelInteractionResponseFormat; import com.google.genai.gaos.models.interactions.FileSearch; import com.google.genai.gaos.models.interactions.Interaction; import com.google.genai.gaos.models.interactions.InteractionsInput; import com.google.genai.gaos.models.interactions.Model; import com.google.genai.gaos.models.interactions.ResponseFormat; import com.google.genai.gaos.models.interactions.TextResponseFormat; import com.google.genai.gaos.models.interactions.TextResponseFormatMimeType; import com.google.genai.gaos.models.operations.CreateInteractionRequestBody; import java.util.Arrays; import java.util.HashMap; import java.util.Map; Client client = new Client(); Map properties = new HashMap<>(); Map amountProp = new HashMap<>(); amountProp.put("type", "string"); amountProp.put("description", "The numerical part of the amount."); properties.put("amount", amountProp); Map currencyProp = new HashMap<>(); currencyProp.put("type", "string"); currencyProp.put("description", "The currency of amount."); properties.put("currency", currencyProp); Map moneyJsonSchema = new HashMap<>(); moneyJsonSchema.put("type", "object"); moneyJsonSchema.put("properties", properties); moneyJsonSchema.put("required", Arrays.asList("amount", "currency")); CreateModelInteractionResponseFormat format = CreateModelInteractionResponseFormat.of( ResponseFormat.of( TextResponseFormat.builder() .mimeType(TextResponseFormatMimeType.APPLICATION_JSON) .schema(moneyJsonSchema) .build())); CreateModelInteraction params = CreateModelInteraction.builder() .model(Model.of("gemini-3.8-flash")) .input(InteractionsInput.of("What is the minimum hourly wage in Tokyo right now?")) .tools( Arrays.asList( FileSearch.builder() .fileSearchStoreNames(Arrays.asList("fileSearchStores/myfilesearchstore123")) .build())) .responseFormat(format) .build(); Interaction interaction = client.interactions.create(CreateInteractionRequestBody.of(params)).interaction().get(); System.out.println(interaction.outputText().orElse("")); ``` {% /tab %} {% tab label="Go" %} ```go package main import ( "context" "fmt" "log" "google.golang.org/genai" "google.golang.org/genai/interactions/models/interactions" "google.golang.org/genai/interactions/models/operations" ) func main() { ctx := context.Background() client, err := genai.NewClient(ctx, nil) if err != nil { log.Fatal(err) } moneyJsonSchema := map[string]any{ "type": "object", "properties": map[string]any{ "amount": map[string]any{ "type": "string", "description": "The numerical part of the amount.", }, "currency": map[string]any{ "type": "string", "description": "The currency of amount.", }, }, "required": []string{"amount", "currency"}, } format := interactions.NewCreateModelInteractionResponseFormat( interactions.NewResponseFormat(interactions.TextResponseFormat{ MimeType: interactions.TextResponseFormatMimeTypeApplicationJSON.ToPointer(), Schema: moneyJsonSchema, }), ) resp, err := client.Interactions.Create(ctx, operations.CreateInteractionRequest{ Body: operations.NewCreateInteractionRequestBody( interactions.CreateModelInteraction{ Model: interactions.Model("gemini-3.8-flash"), Input: interactions.NewInteractionsInput("What is the minimum hourly wage in Tokyo right now?"), Tools: []interactions.Tool{ interactions.NewTool(interactions.FileSearch{ FileSearchStoreNames: []string{"fileSearchStores/myfilesearchstore123"}, }), }, ResponseFormat: &format, }, ), }) if err != nil { log.Fatal(err) } fmt.Println(resp.Interaction.GetOutputText()) } ``` {% /tab %} {% tab label="REST" %} ```bash curl "https://generativelanguage.googleapis.com/v1beta/interactions" \ -H "x-goog-api-key: $GEMINI_API_KEY" \ -H 'Content-Type: application/json' \ -H "Api-Revision: 2026-05-20" \ -X POST \ -d '{ "model": "gemini-3.8-flash", "input": "What is the minimum hourly wage in Tokyo right now?", "tools": [{ "type": "file_search", "file_search_store_names": ["'$FILE_SEARCH_STORE_NAME'"] }], "response_format": { "type": "text", "mime_type": "application/json", "schema": { "type": "object", "properties": { "amount": {"type": "string", "description": "The numerical part of the amount."}, "currency": {"type": "string", "description": "The currency of amount."} }, "required": ["amount", "currency"] } } }' ``` {% /tab %} {% /tabs %} ## Supported models {% id="supported-models" %} The following models support File Search: | Model | File Search | | --- | :---: | | [Gemini 4 Argon](/docs/models/gemini-4-argon) | ✔️ | | [Gemini 3.8 Flash](/docs/models/gemini-3.8-flash) | ✔️ | | [Gemini 3.6 Flash](/docs/models/gemini-3.6-flash) | ✔️ | | [Gemini 3.5 Flash-Lite](/docs/models/gemini-3.5-flash-lite) | ✔️ | | [Gemini 3.1 Pro Preview](/docs/models/gemini-3.1-pro-preview) | ✔️ | | [Gemini 3.1 Flash-Lite](/docs/models/gemini-3.1-flash-lite) | ✔️ | | [Gemini 3 Flash Preview](/docs/models/gemini-3-flash-preview) | ✔️ | | [Gemini 2.5 Pro](/docs/models/gemini-2.5-pro) | ✔️ | | [Gemini 2.5 Flash-Lite](/docs/models/gemini-2.5-flash-lite) | ✔️ | ## Supported tool combinations {% id="tool-combination" %} Gemini 4 and Gemini 3 models support combining built-in tools (like File Search) with custom tools (function calling). Learn more on the [tool combinations](/docs/tool-combination) page. ## Supported file types {% id="supported-files" %} File Search supports a wide range of file formats, listed in the following sections. ## Limitations {% id="limitations" %} * **Live API:** File Search is not supported in the [Live API](/docs/live-api). * **Tool incompatibility:** File Search cannot be combined with other tools like [Grounding with Google Search](/docs/google-search), [URL Context](/docs/url-context), etc. at this time. ### Rate limits {% id="rate-limits" %} The File Search API has the following limits to enforce service stability: * **Maximum file size / per document limit**: 100 MB * **Total size of project File Search stores** (based on user tier): * **Free**: 1 GB * **Tier 1**: 10 GB * **Tier 2**: 100 GB * **Tier 3**: 1 TB * **Recommendation**: Limit the size of each File Search store to under 20 GB to ensure optimal retrieval latencies. {% callout type="note" %} The limit on File Search store size is computed on the backend, based on the size of your input plus the embeddings generated and stored with it. This is typically approximately 3 times the size of your input data. {% /callout %} ## Pricing {% id="pricing" %} * You are charged for embeddings at indexing time based on existing [embeddings pricing](/docs/pricing#gemini-embedding-2). * Storage is free of charge. * Query time embeddings are free of charge. * Retrieved document tokens are charged as regular [context tokens](/docs/tokens). ## What's next {% id="whats-next" %} * Visit the API reference for [File Search Stores](https://ai.google.dev/api/file-search/file-search-stores) and File Search [Documents](https://ai.google.dev/api/file-search/documents).