> ## AI Agent Context
> Get the complete documentation index at: https://aistudio.google.com/llms.txt
> Use this file to discover all available pages.
> For the full documentation in a single file, fetch: https://aistudio.google.com/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.


![The indexing and querying process of File Search](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<String, Object> properties = new HashMap<>();
  
  Map<String, Object> amountProp = new HashMap<>();
  amountProp.put("type", "string");
  amountProp.put("description", "The numerical part of the amount.");
  properties.put("amount", amountProp);
  
  Map<String, Object> currencyProp = new HashMap<>();
  currencyProp.put("type", "string");
  currencyProp.put("description", "The currency of amount.");
  properties.put("currency", currencyProp);
  
  Map<String, Object> 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).

