Prompt Caching

Production & Deployment · AI Engineer Help

Prompt caching: what breaks it, what it saves, and what we measured

Most production prompts repeat thousands of tokens on every call: instructions, tool definitions, policies, examples. Prompt caching lets the provider skip re-reading that repeated part, at up to a tenth of the price. But it only works if the repeated part comes first and stays byte-for-byte identical. A single timestamp in the wrong place switches it off without any error.

Key takeaways

  1. A prompt cache is a prefix match. The provider reuses work only for the leading part of your prompt that is identical to an earlier request. The first changed character ends the reusable part, and everything after it is processed at full price.
  2. Where the changing parts sit decides what can be cached. In our test prompt, a timestamp on the first line of the system instruction cut the reusable prefix from 5,382 tokens (99.7%) to 783 (14.4%). The same timestamp at the end of the user message left 5,403 tokens (99.5%) reusable.
  3. Small, invisible differences break it too. Sending the same seven tools in a different order left 11 reusable tokens. Putting the question before the handbook left 1,086. Both are below Gemini's 4,096-token minimum, so nothing at all could be cached.
  4. Gemini's implicit caching gave us nothing. In 97 eligible requests with byte-identical 5,400 to 13,000-token prefixes, sent seconds apart, we got zero implicit cache hits. Google documents implicit caching as having "no cost saving guarantee".
  5. Explicit caching delivered every time. With a cache created through Gemini's cachedContents API, 12 of 12 requests read 5,384 of about 5,400 prompt tokens from cache. That cut the cost per request, including output, by 84%, from $0.00439 to $0.00072.
  6. We saw no latency gain at this size. Median time to first token was 2.3 s with the explicit cache and 2.1 s without one. Providers say the speed-up shows on long prompts; at 5,400 tokens, network and generation time dominate.

What prompt caching is

A model handles a request in two phases. First it reads the whole prompt (the prefill) and builds an internal representation of every token, called the key-value (KV) cache. Then it generates the answer one token at a time (the decode). Prefill is the part you pay input prices for, and for long prompts it is a large share of the time before the first token appears.

If two requests start with the same tokens, the representation of those tokens is identical too, because each token's representation depends only on the tokens before it. Prompt caching keeps that work for a few minutes and reuses it when another request starts the same way. The model still sees the full prompt, so answers don't change. Only the price and the prefill time do.

It's easy to confuse with two other kinds of caching:

KindWhat is reusedWhen it appliesDoes the model run?
Prompt cachingThe provider's processed prompt prefixA new request starts with exactly the same tokensYes, on the full prompt, so answers are as fresh as without a cache
Response cachingA stored answer, on your sideThe whole request is identicalNo. The stored answer is returned
Semantic cachingA stored answer, on your sideA new question means roughly the same as an old oneNo. A similar but different question can get a wrong stored answer

Table 1. Prompt caching is the only one of the three that never changes what the model says. That makes it safe to turn on everywhere.

The one rule: prefix match

Everything in this article follows from one rule: the cache matches from the first token forward, and stops at the first difference. It doesn't look for the longest matching chunk somewhere in the middle. If request 2 differs from request 1 at token 50, only the first 49 tokens can be reused, even if the next 5,000 are identical.

Figure 1. Two requests, one timestamp

Each box is a chunk of the prompt, in the order the model reads it.

Read from cacheProcessed at full price
Request 2 changes two digits, but from that point on nothing matches, so the handbook after it is processed again. Moving the time to the end makes the handbook reusable. The model still sees the time.

Two consequences matter in practice:

Figure 2. The same content in two orders

Retrieval apps often put the question first. Moving it last turns the documents into a reusable prefix.

Question first

Instructions 300
User question 20
Handbook and examples 4,400

Question last

Instructions 300
Handbook and examples 4,400
User question 20
Token counts are approximate. The left layout has a 300-token reusable prefix, below every provider's minimum, so nothing is cached at all.

How each provider does it

All three providers cache prefixes, but they differ in whether you have to ask, what a write costs, and how long an entry lives. Prices below are list prices per million input tokens, checked on 7 October 2026.

Anthropic ClaudeGoogle GeminiOpenAI
How to turn it onMark up to 4 breakpoints with cache_control, or set it once at the top level for automatic placementImplicit: on by default, best effort. Explicit: create a cachedContents resource and reference itAutomatic on supported models. GPT-5.6 and later also accept explicit breakpoints
Cache read price0.1× input (Sonnet 5.5: $0.20 vs $2). Opus 5.5: 0.05×0.1× input (3.8 Flash: $0.075 vs $0.75)0.1× input on most models, 0.05× on GPT-6.1 Sol
Cache write price1.25× input (5-minute entry) or 2× (1-hour entry)Implicit: none. Explicit: storage at $0.50 per million tokens per hour (3.8 Flash)GPT-5.6 and later: 1.25× input. Earlier models: none
Minimum prompt512 tokens (Opus 5.5, Sonnet 5.5), 4,096 (Haiku 4.5)4,096 tokens (3.x Flash and Pro), 2,048 (2.5)1,024 tokens (GPT-5.6 and later)
Lifetime5 minutes, reset on every hit; 1 hour optionalImplicit: not documented. Explicit: you set it (default 1 hour)30 minutes (GPT-5.6 and later)
How to check hitsusage.cache_read_input_tokens, cache_creation_input_tokensusageMetadata.cachedContentTokenCount, or usage.total_cached_tokens in the Interactions APIusage.input_tokens_details.cached_tokens and cache_write_tokens

Table 2. Sources: Claude prompt caching and pricing; Gemini caching, explicit caching and pricing (3.8 Flash prices are promotional through 31 December 2026); OpenAI prompt caching and pricing. Prices and minimums change, so check them before you rely on them.

Where a write costs extra, caching pays off only if the entry is read again before it expires. On Claude, the docs work out that a 5-minute entry breaks even after one read, since 1.25× + 0.1× is less than 2×, and a 1-hour entry after two reads. For Gemini's explicit cache, here is our own calculation from the prices above. Each cached read of our 5,384-token prefix saves $0.0036, and storing it costs $0.0027 an hour. So it pays off from about one request per hour.

Eight ways to break the cache

None of these produce an error. The request succeeds, the answer is fine, and the bill is higher. Each one has a matching example in the playground.

01The current time at the top

The most common case. A template starts with Current time: {now} so the model knows the date. If the time includes seconds, no two requests share more than the text before it.

Breaks the cache

Current time: 2026-10-07T14:32:09Z
You are the support assistant…
[4,000-token handbook]

Cacheable

You are the support assistant…
[4,000-token handbook]
…
User: Today's date: 7 October 2026
Where is my order?

Measured: the reusable prefix fell from 5,382 to 783 tokens. Also ask whether the model needs seconds at all. A date changes once a day, so it splits the cache once a day instead of on every request. Try it →

02User details in the system prompt

You are helping {name} ({email}), a Gold member. Every user gets a different prefix, so the instructions after it are cached once per user instead of once for everyone. Within one user's conversation the cache still works, which hides the problem in testing.

Measured: the reusable prefix across users fell from 5,389 tokens (details at the end) to 774 (details at the top). Try it →

03Request IDs, counters and budgets

Agent loops often write state into the system prompt: request_id, Turn 4 of 20, Tokens remaining: 18,240. Each one is unique per call. Send IDs as request metadata, and put state the model needs in the latest message. Try it →

04Tools in a different order

Building the tool list from a dictionary, a set or a plugin registry can change its order between processes or deployments. The tools are the same, but the bytes aren't, and tools sit at the very front of the prompt.

Measured: the same seven tools, shuffled per request, left a reusable prefix of 11 tokens. Sort tools by name, and serialize JSON with sorted keys.

05Different tools for different users

Hiding tools a user isn't allowed to use is tempting, but it gives each permission level its own prefix, starting from the first token. Keep one tool set for everyone and check permissions when a tool is called. That is also the safer design. Try it →

06The question before the documents

Retrieval prompts often read "Question: … Context: …". If the documents are the same across requests, as with a policy handbook or a product manual, they should come first. Documents retrieved per query can't be shared across users anyway, but they can still be cached within a conversation if earlier turns don't change.

Measured: 1,086 reusable tokens, below Gemini's 4,096 minimum, so none were cacheable. Try it →

07Changing model or settings mid-conversation

Caches belong to one model, so routing a follow-up to a cheaper model starts from zero. On Claude, changing tool_choice, images or thinking settings also invalidates part of the cache (see the "invalidation" section of Anthropic's docs). Pick the model and settings per route, not per request.

08Parallel requests and long gaps

A cache entry can only be read after the request that writes it has started responding. If you send 20 requests with the same prefix at once, all 20 pay full price. Send one first, then the rest. At the other end, traffic slower than the cache lifetime never hits. On Claude, an entry lives 5 minutes after its last use, so a chatbot that gets one message every 10 minutes caches nothing unless it uses the 1-hour option.

The experiment

Docs describe the rules. We wanted to see them in real requests: how much of a realistic prompt each layout leaves reusable, whether the provider actually caches it, and what that does to cost and latency. We had Gemini API access, so we ran on Gemini 3.8 Flash (gemini-3.8-flash), on 7 October 2026.

The prompt

A customer-support assistant for Northwind Outfitters, a fictional outdoor-gear store. Every layout sends the same parts:

PartWhat it containsCharacters
InstructionsRole, tone, how to cite policy sections, what never to do1,211
Policy handbook12 sections: orders, shipping, returns, refunds, warranty, trade-in, loyalty, care and sizing, privacy, escalation, a 27-product reference table and common questions15,940
ToolsSeven function declarations: cancel_order, create_return, escalate_to_human, lookup_order, open_warranty_claim, search_products, track_parcel3,054
ExamplesFour example exchanges showing tone and length1,499
QuestionOne of 12 customer questions, such as "Can I return a tent I set up once in my garden?"32–73

Table 3. Gemini counted about 5,400 prompt tokens per request, comfortably above the 4,096-token minimum. The full text is in src/fixture.js.

Eight layouts

LayoutWhat changes between requests, and where

Table 4. Each layout starts its system instruction with a tag that is fixed within the layout, such as deployment r202610079c02-stable. It stops layouts from reading each other's cache, the way two separate applications wouldn't share one.

Procedure and measures

We also sent a 2-request smoke test before the run. When implicit caching produced no hits, we sent 12 follow-up requests. They varied one thing at a time: no streaming; no tools and no thinking setting; a prompt three times larger (13,100 tokens); and Google's newer Interactions API.

Results

Figure 3. How much of each prompt could be reused

Median reusable prefix: the share of the prompt identical to the previous request, from the first character.

Above Gemini's 4,096-token minimumBelow the minimum: nothing cacheable
Every layout sent the same content. Only the position of the changing parts differed. For the explicit cache, the bar shows the stored part. Source: results/summary.json.

The layout result is exactly what the prefix rule predicts. Moving the changing value to the end kept 99.4–99.7% of the prompt reusable. Putting it at the top cut that to 14%. The shuffled tools cut it to almost nothing, because the tools are the first thing in the prompt.

Figure 4. Cached tokens on each request

Stable prefix (implicit caching) vs explicit cache, 12 requests each, in order.

Explicit cacheStable prefix, implicit caching
All 12 explicit requests read 5,384 tokens from cache. All 12 implicit requests read none, and neither did the other 72 requests in the run, or any of the 13 smoke-test and follow-up requests that succeeded.
Measured

Implicit caching: 0 hits in 97 eligible requests. These were 84 requests in the main run, 2 in the smoke test and 11 successful follow-ups (one Interactions API request failed with an unrelated error). They used streaming and non-streaming, with and without tools, prompts from 4,500 to 13,100 tokens, and both the generateContent and Interactions APIs. Prefixes were byte-identical, and requests were seconds apart. Explicit caching: 12 hits in 12 requests, each reading 5,384 tokens (99.7% of the prompt) from cache.

Figure 5. Cost per request

Measured cost, input plus output, at Gemini 3.8 Flash list prices. Explicit includes storage.

Because implicit caching never hit, every implicit layout cost the same, about $0.0044 per request. The explicit cache cost $0.00072, 84% less. Its input alone fell 90%. Storing the 5,384-token cache for its 1.1 minutes cost $0.00005.

Figure 6. Time to first token

Each dot is one request. The line marks the median. Two slow outliers (23.0 s and 14.8 s) are drawn at the edge.

Cached and uncached requests had overlapping ranges. The explicit cache's median (2.3 s) was not faster than the stable prefix without hits (2.1 s).
LayoutPrompt tokensReusable prefixCache hitsCached shareFirst token (median)Cost / request

Table 5. All 96 requests, by layout (medians, 12 requests each). Every request and every answer is in results/requests.jsonl. 16 of the 96 responses were tool calls, all to lookup_order, for questions that named an order.

What it would have saved

The reusable prefix tells you what a working cache could save. If every request's reusable prefix had been read from cache at the cached price, here is the input cost of 1,000 requests. This is a projection from the measured prefixes, not a measurement:

LayoutWithout cacheReusable prefix cachedSaving

Table 6. Layouts with a reusable prefix below 4,096 tokens save nothing. That isn't because 783 tokens wouldn't help, but because Gemini won't cache a prefix that short.

Why it happens

Interpretation

Why implicit caching missed. We can only guess, because Google doesn't publish how implicit caching decides. Caches like this usually live on individual serving machines. A hit needs the next request to reach a machine that still holds the prefix. OpenAI's docs say this for their own cache: routing uses a hash of the first tokens, and "traffic above 15 requests per minute can lead to overflow routing" to other machines. Our traffic was light: about 14 requests a minute in total, and each layout's prefix was used for under two minutes. With so little traffic, a provider may not keep a prefix warm at all, or the next request may land on a different machine. It could also depend on load, region or account. Whatever the reason, implicit caching is best effort, and you can't plan costs around it until you've measured it on your own traffic.

Interpretation

Why the cache didn't make responses faster. Reading 5,400 tokens is quick on current hardware. Time to first token also includes network time, queueing, a short thinking step and, for tool calls, generating the call. So the prefill saving was smaller than the normal variation between requests (1.5 to 4.7 s, plus two outliers). Anthropic's docs say you will "generally see improved time-to-first-token for long documents", so expect latency gains at tens of thousands of tokens, not at five thousand.

Practical advice

  1. Design the prompt as layers: tools and instructions, then shared documents and examples, then per-user context, then conversation history, then the new message. Put anything with a clock, an ID or a counter in the last layer.
  2. Make serialization deterministic. Sort tools by name and JSON keys alphabetically. Never build prompt text by iterating a set. Strip trailing whitespace consistently.
  3. Pass dynamic context late. On Claude models that support it, a mid-conversation system message is designed for this: it adds instructions after the cached history instead of editing the top. Elsewhere, put it in the user message.
  4. Choose explicit caching when the saving matters. On Gemini, create a cache for any large prefix you reuse more than about once an hour. On Claude, add cache_control at the end of the stable part.
  5. Measure hits on every request. Log cached tokens next to total input tokens and alert when the ratio drops. Caching regressions don't fail; a deploy that adds a timestamp only shows up on the bill.
  6. Warm up before fan-out. Send one request, wait for its first token, then send the parallel requests.
  7. Check the minimum. A 3,000-token prompt caches on Claude Sonnet 5.5 (512 minimum) and never on Gemini 3.8 Flash (4,096) or Claude Haiku 4.5 (4,096).

What it looks like in code

Claude, with an explicit breakpoint at the end of the stable system prompt (Python SDK):

response = client.messages.create(
    model="claude-sonnet-5-5",
    max_tokens=1024,
    tools=sorted(TOOLS, key=lambda t: t["name"]),   # same order every time
    system=[{
        "type": "text",
        "text": INSTRUCTIONS + HANDBOOK,             # no dates, IDs or names in here
        "cache_control": {"type": "ephemeral"},      # cache everything up to this point
    }],
    messages=[{"role": "user", "content": f"Today's date: {today}\n\n{question}"}],
)
print(response.usage.cache_read_input_tokens, response.usage.cache_creation_input_tokens)

Gemini, with an explicit cache (REST, as used in our experiment):

# 1. Store the stable part once (default lifetime: 1 hour)
POST /v1beta/cachedContents
{ "model": "models/gemini-3.8-flash",
  "systemInstruction": { "parts": [{ "text": "<instructions + handbook + examples>" }] },
  "tools": [{ "functionDeclarations": [ ... ] }],
  "ttl": "600s" }

# 2. Each request sends only the new part and the cache name
POST /v1beta/models/gemini-3.8-flash:generateContent
{ "cachedContent": "cachedContents/abc123",
  "contents": [{ "role": "user", "parts": [{ "text": "Can I return a tent?" }] }] }
# → usageMetadata.cachedContentTokenCount: 5384

OpenAI caches automatically. Check usage.input_tokens_details.cached_tokens, and on GPT-5.6 and later also cache_write_tokens. The ordering rules are the same.

Limitations

Reproduce it

Everything runs with Node.js 20 or later and no dependencies. From production-deployment/prompt-caching/:

npm test                          # 17 tests for the analyzer and cost model
npm start                         # this article and the playground at http://127.0.0.1:4321
npm run experiment                # dry run: prints the plan and the worst-case cost
cp .env.example .env              # add GEMINI_API_KEY
npm run experiment -- --live      # 96 paid requests, about $0.40
npm run analyze                   # writes results/summary.json, requests.jsonl, report.md

The main run cost $0.38. With the smoke test and follow-ups, the total was about $0.46.

Sources

  1. Anthropic, Prompt caching and Pricing, accessed 7 October 2026.
  2. Google, Context caching (Interactions API), last updated 2 September 2026; Context caching (generateContent), 11 September 2026; Pricing, 6 October 2026.
  3. OpenAI, Prompt caching and Pricing, accessed 7 October 2026.