OpenAI's demo relies on automatic prefix caching. Gemini can also reuse common prefixes implicitly, but its explicit context-caching API exposes a different application model.

The application creates a named cache resource, chooses its lifetime, and refers to that resource from later generation requests.

That makes caching visible as lifecycle-managed infrastructure.

First: What Is Gemini Context Caching?

Gemini context caching lets an application upload a substantial stable context once and reuse it across shorter requests.

stable policy
     ↓
create cached content resource
     ↓
cachedContents/policy-1
     ↓
question A ─┐
question B ─┼→ generate with cached_content
question C ─┘

The cached content becomes a prefix to each generation request. The model still reasons over it together with the new question.

Implicit and Explicit Caching Are Different Paths

Gemini 2.5 and newer models support implicit caching automatically. The application sends the repeated prefix normally and may receive cache savings when a match occurs.

Explicit caching adds a resource API:

IMPLICIT
send full common prefix repeatedly
provider may reuse it automatically

EXPLICIT
create named cache once
send cache name with later questions
manage TTL and cleanup

The project compares a no-explicit-cache baseline with two explicit cache resources.

Creating the Cache

The stable policy and system instruction are provided during cache creation:

cache = client.caches.create(
    model=model,
    config=types.CreateCachedContentConfig(
        display_name=label,
        system_instruction=SYSTEM,
        contents=[policy],
        ttl="300s",
    ),
)

The returned cache.name is the durable handle for subsequent requests:

cachedContents/...

The demo validates that a name exists before continuing. A cache without a usable identifier cannot be referenced safely.

The TTL Is Part of the Cost Decision

The project uses a five-minute lifetime:

ttl="300s"

Gemini bills explicit-cache storage according to cached token count and storage duration, in addition to generation charges. A longer TTL creates a larger reuse window and more storage duration.

short TTL
→ smaller storage window
→ cache may expire before later work

long TTL
→ larger reuse window
→ more storage duration

The right value depends on request frequency and current model pricing. It should be chosen from expected reuse rather than convenience alone.

Cached Requests Send Only the Changing Case

Without an explicit cache, the request includes policy and question:

contents = f"{policy}\n\nCustomer question: {case}"
config = types.GenerateContentConfig(
    system_instruction=SYSTEM,
)

With a named cache, the stable content is already attached to the resource:

contents = f"Customer question: {case}"
config = types.GenerateContentConfig(
    cached_content=cache_name,
)

That difference is application-visible. The cached path does not resend the policy string from the local process on each generation call.

Minimum Cache Size Matters

Explicit cache creation is model-specific and requires enough input tokens.

The current Gemini documentation lists a 2,048-token minimum for Gemini 2.5 Flash and Gemini 2.5 Pro. The project's 75-rule fictional policy was expanded to clear that threshold for the default gemini-2.5-flash model.

policy below model minimum
→ cache creation rejected

policy above model minimum
→ cache can be created

This limit can vary by model. Applications should verify the current documentation when changing models rather than carrying one constant forever.

The Same Policy Revision Reuses One Resource

The explicit-cache phase creates revision A once and asks five questions against its name:

create cache(policy revision A)
              ↓
question 1 ───┤
question 2 ───┤
question 3 ───┤→ same cached_content name
question 4 ───┤
question 5 ───┘

The cache resource is immutable context for those requests. The variable case remains outside it.

A Policy Revision Becomes a New Cache

The project changes the revision marker near the beginning:

changed = POLICY.replace(
    "revision 2026-09-A",
    "revision 2026-09-B",
    1,
)

It then creates another resource:

cachedContents/policy-A → old policy
cachedContents/policy-B → revised policy

This is safer than pretending an old name now represents different content. The application can associate every request with the exact policy revision it used.

Usage Metadata Shows the Reuse

The script reads:

usage = response.usage_metadata

prompt_tokens = usage.prompt_token_count or 0
cached_tokens = usage.cached_content_token_count or 0
output_tokens = usage.candidates_token_count or 0

Cached content tokens are included in prompt tokens.

prompt tokens = cached content + new prompt content

The demo reports the cached share:

total_cached / total_prompt

As with OpenAI, token metadata is the evidence. A latency difference by itself cannot prove cache reuse.

Controlled Output From the Real Gemini Flow

I ran the project's real run(), create_cache(), show_phase(), ask(), and usage-reading code against a deterministic offline Gemini client fixture.

The fixture made no network requests and incurred no provider charges. It returned controlled usage metadata so cache creation, reuse, revision, aggregation, and cleanup could be exercised end to end.

Phase 1: no explicit cache
  1: 2300 prompt, 0 cached, 40 output, 0.25s
  2: 2300 prompt, 0 cached, 40 output, 0.25s
  3: 2300 prompt, 0 cached, 40 output, 0.25s
  4: 2300 prompt, 0 cached, 40 output, 0.25s
  5: 2300 prompt, 0 cached, 40 output, 0.25s
  cached share 0.0%; mean latency 0.25s

Phase 2: create explicit cache for policy revision A
  created cachedContents/policy-1; cached policy tokens: 2200

Phase 2: reuse revision A cache
  1: 2300 prompt, 2200 cached, 40 output, 0.25s
  2: 2300 prompt, 2200 cached, 40 output, 0.25s
  3: 2300 prompt, 2200 cached, 40 output, 0.25s
  4: 2300 prompt, 2200 cached, 40 output, 0.25s
  5: 2300 prompt, 2200 cached, 40 output, 0.25s
  cached share 95.7%; mean latency 0.25s

Phase 3: policy revision B requires a new cache
  created cachedContents/policy-2; cached policy tokens: 2200

Phase 3: reuse revision B cache
  1: 2300 prompt, 2200 cached, 40 output, 0.25s
  2: 2300 prompt, 2200 cached, 40 output, 0.25s
  cached share 95.7%; mean latency 0.25s

The totals and cleanup were:

no explicit prompt=11500 cached=0     output=200
cached A    prompt=11500 cached=11000 output=200
cached B    prompt=4600  cached=4400  output=80

Deleted cachedContents/policy-1
Deleted cachedContents/policy-2

These are controlled fixture values that demonstrate application behavior. A live run must use the provider's returned usage metadata and current pricing.

Cleanup Belongs in finally

The demo tracks every created cache name and deletes it even if a later generation call raises an error:

caches = []
try:
    # create and use caches
finally:
    for name in caches:
        client.caches.delete(name=name)

If deletion fails, the script reports that condition and relies on the five-minute TTL.

This is the same resource-management rule used for files, database connections, and temporary infrastructure: creation requires an explicit cleanup path.

Cache Creation Is Not Free Preprocessing

An explicit cache can introduce:

  • a cache-creation API call
  • cached-input charges
  • storage-duration charges
  • ordinary non-cached input charges
  • output-token charges
  • lifecycle and cleanup work

The relevant comparison is total workload cost across expected reuse, not the price of one cached generation call in isolation.

few requests
→ creation and storage may not pay back

many requests sharing large context
→ explicit caching may become useful

Model Support Must Be Checked

The demo intentionally targets gemini-2.5-flash, which supports explicit caching.

Google's current documentation marks explicit context caching as beta and states that Gemini 4 Argon and later Gemini 4 models use implicit caching rather than the explicit cachedContents flow.

An application changing model families must revalidate:

  • whether explicit caching is supported
  • minimum cached-token count
  • TTL behavior
  • SDK and API version
  • usage metadata fields
  • current pricing

Trust Still Depends on Prompt Structure

The cached content contains a fictional support policy and a system instruction that treats each customer message as case data rather than policy.

cached trusted policy
        +
changing untrusted customer case
        ↓
generation

Caching does not create the trust boundary. It preserves the prompt structure that the application already chose. Putting untrusted user content inside a broadly reused cache would be a design error.

What the Tests Prove

The Gemini portion has three offline tests. They verify that:

  • the uncached request contains both policy and question
  • the explicit-cache request sends only the question and cache name
  • cached-token usage is read from Gemini metadata
  • cache creation receives the policy and five-minute TTL

The combined project run completed with:

Ran 5 tests in 0.001s
OK

The tests validate integration logic without creating billable caches. A separate live experiment is needed to observe real cache token counts.

OpenAI and Gemini Side by Side

OPENAI                              GEMINI EXPLICIT CACHE

automatic eligible prefix reuse    named cache resource
normal generation request          create then reference cache
provider-managed lifetime          application-selected TTL
no cache deletion call             explicit deletion or expiry
cached_tokens in response usage    cached_content_token_count

Both systems reward stable shared context followed by changing input. Their lifecycle and billing models are different enough that one abstraction should not hide the provider-specific details.

What I Took Away

Gemini explicit caching turns repeated context into a managed resource.

identify substantial stable context
create a versioned cache
reuse its name across changing requests
measure cached tokens
delete it or let its TTL expire

That control is useful when reuse is predictable. It also makes the application responsible for cache creation, revision naming, TTL choice, cleanup, and cost measurement.

Source Code

The complete project includes explicit cache creation, revision-specific resources, five-minute TTLs, usage aggregation, cleanup in finally, the OpenAI comparison, and offline tests.

GITHUB / SOURCE CODEExplore the Gemini context-caching implementationsriraman-10 / applied-ai-concepts / prompt-caching / gemini.py

References

GOOGLE AI DOCS / CONTEXT CACHINGGemini context cachingImplicit caching, explicit cache resources, minimum sizes, TTL, usage, and billingGOOGLE AI DOCS / PRICINGGemini API pricingCurrent cached-input and storage pricing by model