GEMINI LABJP
AGENT — Managed Agents enter public preview in the Gemini API, running autonomous, stateful agents in isolated Google-hosted Linux sandboxesSEARCH — File Search now supports multimodal search, natively embedding and searching images with gemini-embedding-2 (GA)TTS — gemini-3.1-flash-tts-preview now streams speech generation for lower-latency playbackMODEL — Gemini 3.5 Flash reaches GA and now powers gemini-flash-latestDEPRECATION — Image generation models are scheduled to shut down on August 17, 2026; plan your migrationENTERPRISE — Gemini 3.5 Flash is generally available across the Global, US, and EU regions on Gemini EnterpriseAGENT — Managed Agents enter public preview in the Gemini API, running autonomous, stateful agents in isolated Google-hosted Linux sandboxesSEARCH — File Search now supports multimodal search, natively embedding and searching images with gemini-embedding-2 (GA)TTS — gemini-3.1-flash-tts-preview now streams speech generation for lower-latency playbackMODEL — Gemini 3.5 Flash reaches GA and now powers gemini-flash-latestDEPRECATION — Image generation models are scheduled to shut down on August 17, 2026; plan your migrationENTERPRISE — Gemini 3.5 Flash is generally available across the Global, US, and EU regions on Gemini Enterprise
Articles/Advanced
Advanced/2026-07-08Advanced

One File Search Store for Many Apps: Splitting Retrieval With customMetadata and Chunk Config

Put several apps' FAQs in a single Gemini File Search store and metadataFilter can silently return empty grounding, or answers get split across chunk boundaries. Here is the customMetadata design, the AIP-160 filter-syntax trap, and measured chunkingConfig tuning.

Gemini API172File Search5RAG12customMetadataindie development8

Premium Article

When I first moved my apps' help FAQs into Gemini's File Search, I gave each app its own store. Wallpaper app, relaxation app, one store each. It felt like the obvious layout.

In practice, every extra store meant another re-indexing job and another thing to track. Fixing a single FAQ line meant first remembering which store it lived in. As an indie developer running several apps alone, that small tax adds up.

So I switched to putting every app's FAQ in one store and narrowing by app only at query time. File Search offers customMetadata and metadataFilter. Tag each document with app_id, filter on app_id at query time, and a single store should never bleed one app's answers into another.

Should. I say "should" because metadataFilter kept returning empty answers with no exception and no warning. This article walks through how I isolated that, plus a second issue I found along the way: answers getting dropped when they split across a chunk boundary, and how I tuned it with real numbers.

Why merge into one store — an indie developer's call

Split stores or one shared store? For a solo developer, that decision is settled less by "what is correct" and more by "what I can keep maintaining."

A File Search store is a container that persists embeddings. Raw files are deleted after 48 hours, but the embeddings you import stay until you delete them manually. So a store is an object where every new one adds another target for deletion and re-import.

The docs note that a store's size is roughly three times the input (input plus generated embeddings), and recommend keeping each store under 20 GB. For indie-scale FAQs, size is never the problem. The count is.

My rule became: split by update frequency and isolation requirements, not by data volume. Things I edit constantly and must never mix between apps — like FAQs — go into one shared store and are separated logically by app_id. Blocks that need a different embedding model or a different re-indexing strategy get their own physical store. "Physical split only when forced, logical split by metadata" is the line I found easiest to sustain.

Store staleness itself is a separate topic; I wrote up drift detection in a note on File Search stores quietly going stale in production. This article stays focused on the shared-store case.

Separating apps with customMetadata

Isolation starts with the customMetadata you attach at import time — key/value pairs, up to 20 per document.

from google import genai
import time
 
client = genai.Client()
 
# Use the multimodal embedding model so images can live here too
store = client.file_search_stores.create(
    config={
        "display_name": "app-faqs-shared",
        "embedding_model": "models/gemini-embedding-2",
    }
)
 
def import_faq(path: str, app_id: str, kind: str, lang: str):
    # Upload via the Files API, then import into the store
    src = client.files.upload(file=path, config={"name": f"faq-{app_id}"})
    op = client.file_search_stores.import_file(
        file_search_store_name=store.name,
        file_name=src.name,
        # The key to separation: attach app_id / kind / lang
        custom_metadata=[
            {"key": "app_id", "string_value": app_id},
            {"key": "kind", "string_value": kind},
            {"key": "lang", "string_value": lang},
        ],
    )
    while not op.done:
        time.sleep(5)
        op = client.operations.get(op)
    return op
 
import_faq("faq_wallpaper_en.md", app_id="wallpaper", kind="faq", lang="en")
import_faq("faq_healing_en.md",   app_id="healing",   kind="faq", lang="en")
# Expect: two documents in one store, each chunk tied to an app_id

One design note that saves regret later: decide the value type up front. Whether app_id is a string or a number changes how you write the metadataFilter below. My rule is that identifiers are always string_value, and only thresholds I want to compare — a year or a version number — use numeric_value. Mix them and you will forget which type a key is when you write the filter.

Thank you for reading this far.

Continue Reading

What follows includes implementation code, benchmarks, and practical content we hope you'll find useful. This site runs without ads — server and development costs are supported entirely by members like you. If it's been helpful, we'd be truly grateful for your support.

WHAT YOU'LL LEARN
If you have been spinning up one File Search store per app and drowning in upkeep, you can switch to a single shared store with metadata-based isolation
You will be able to diagnose why metadataFilter returns empty grounding with no exception, using an AIP-160 syntax isolation procedure
You can stop FAQ answers from being dropped when they straddle a chunk boundary, by tuning max_tokens_per_chunk and overlap against measured results
Secure payment via Stripe · Cancel anytime

Unlock This Article

Get full access to the rest of this article. Buy once, read anytime. This site is ad-free — your support goes directly toward keeping it running.

or
Unlock all articles with Membership →
Share

Thank You for Reading

Gemini Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.

  • Copy-paste ready implementation code
  • New advanced guides published daily
  • $5/mo or $10 for lifetime access
View Membership →

Related Articles

Advanced2026-06-01
Trimming Gemini Embeddings from 3072 to 768 Dimensions: A Matryoshka Approach to Cutting Vector DB Cost and Latency
gemini-embedding-001 returns 3072-dimensional vectors, but thanks to Matryoshka representation you can keep only the leading dimensions with almost no quality loss. This is a design for trimming to 768 to cut vector DB storage and latency, including the re-normalization pitfall and coarse-to-fine search code.
Advanced2026-05-31
The Day You Switch Gemini Embedding Models: Designing a Zero-Downtime Reindex
Upgrade your embedding model and every vector you ever stored becomes incompatible. Here is a dual-index design for re-embedding hundreds of thousands of vectors without downtime, complete with a resumable reindex job and a query-side abstraction layer.
Advanced2026-04-11
Gemma 4 API Advanced Integration Guide: Hybrid Development with Gemini API
Advanced patterns for using Gemma 4 API alongside Gemini API. Covers Vertex AI deployment, fine-tuning, RAG pipelines, and cost optimization strategies.
📚RECOMMENDED BOOKS
Build a Large Language Model (From Scratch)
Sebastian Raschka
LLM Dev
Prompt Engineering for LLMs
Berryman & Ziegler
Prompting
AI Engineering
Chip Huyen
AI Eng
* Contains affiliate links
See all →