CostCompass An Almanac Beta
Engineering Guide

Turn caching on, then prove it works

Adding a cache marker is the easy part. The step that matters is verification — a cache that never reads is not slightly worse, it is pure waste, because on some providers you pay a write premium on every call and collect no discount. This guide walks the five steps end to end, with the exact field to check for each provider.

By Joubert Berger Published July 8, 2026

Most guidance on prompt caching stops at “add the cache marker.” That is the easy part, and it is not the part that goes wrong. The part that goes wrong is silent: you add the marker, the request still succeeds, the bill does not move, and nothing tells you why. On a provider that charges a premium to write a cache entry, a cache that never gets read is worse than not caching at all — you pay the write premium on every call and collect none of the read discount in return.

So this guide treats enabling caching as what it actually is: a five-step procedure whose load-bearing step is not the marker but the verification after it. Structure a stable prefix, turn caching on the way your provider requires, confirm from the response that the cache is being read, measure the net saving, and keep the prefix from silently breaking. This is the how-to companion to Prompt Caching Explained, which covers the economics — the write premium, the read discount, the TTL, and how to tell in advance whether caching will pay off on a given workload. This guide assumes you have already decided caching is worth trying and shows you how to turn it on correctly and prove it. Where a number here is a price or a size that drifts, it is dated and linked to the provider’s own documentation; reverify it before you rely on it.

The running example throughout is a coding agent: a fixed system prompt, a large set of tool definitions, and repository context that repeat on every step, with only the newest user turn changing. That is the archetypal winning shape — a big stable prefix reused many times in quick succession — and it makes each step concrete.

A five-node left-to-right flow of the prompt-caching enablement procedure: structure a stable prefix, enable per provider, verify the cache-read counter, measure the net saving, and keep the prefix from breaking, with the verify step emphasized and a feedback arrow from the last step back to the first.
Figure 1. Enabling prompt caching is five ordered steps — structure a stable prefix, enable it for your provider, verify the cache-read counter, measure the net saving, and keep the prefix from breaking. Verification is the load-bearing step, and the loop back to the start is what keeps caching working over time.

Step 1: Confirm the prerequisites

Before you touch any caching parameter, two things have to be true, and if either is false, caching cannot help yet.

Your request must have a stable leading prefix that repeats across calls. Caching matches the beginning of a request, in order, from the first token, and stops at the first token that differs. So the technique cares about where content sits, not merely whether it repeats: repeated content sitting behind something that changes is not a prefix and earns nothing. The coding agent qualifies — its system prompt, tool definitions, and repository context are identical on every step of a session. A stream of unrelated one-shot prompts does not; there is no shared prefix to reuse.

That prefix must clear the model’s minimum cacheable size. Below a per-model floor, the provider stores nothing, your request still succeeds, and no error is returned — the only symptom is a cache-read counter that never leaves zero. As of July 6, 2026, the floors are:

You also need API access to the response’s usage object, because Step 3’s verification depends on reading the token counts it reports. Every provider covered here returns them by default.

If both prerequisites hold, you have a candidate. The next question is exactly where the stable prefix ends.

Step 2: Identify the stable prefix and the volatile tail

Caching operates on a contiguous prefix, so the single most important structural decision is the order of your request: everything that is identical across calls goes at the front, everything that changes goes at the end. The boundary between them is where a cache marker belongs.

For the coding agent, the stable prefix is the system prompt, the tool definitions, and the repository context, in a fixed order. The volatile tail is the newest user turn and the latest tool result. Mark the boundary at the last token that is identical across requests — not earlier, which leaves cacheable content uncached, and not inside the volatile region, which breaks the match on every call.

The failure that hides here is a single volatile value that has drifted forward into the prefix. A timestamp injected into the system prompt, a request id rendered near the top, a per-user greeting ahead of the shared context, or a JSON object serialized with non-deterministic key order — any one of these changes the leading bytes and forces a fresh write every time, so the cache never reads. The fix is structural, not a setting: move the volatile value behind the boundary so the prefix stays byte-for-byte identical.

A before-and-after of one request band. In the broken version a stray timestamp sits ahead of the stable prefix, so only a tiny leading region is cacheable before the cache breakpoint. In the fixed version the timestamp is moved into the volatile tail, so the whole stable prefix — system prompt, tool definitions, repository context — is cacheable up to the breakpoint.
Figure 2. The cache breakpoint belongs at the last token that is identical across requests. A single volatile value — here a timestamp — sitting ahead of the stable prefix breaks the match and leaves almost nothing cacheable; moving it to the volatile tail restores the full cacheable prefix.

This ordering discipline is the same one the concept guide frames as growing the stable prefix and moving volatile content to the tail; here it is the concrete thing you do before enabling anything. With the boundary identified, you can turn caching on.

Step 3: Enable it for your provider

Providers split into two shapes, and knowing which one you are on tells you whether Step 2’s boundary needs a marker at all.

Automatic caching — nothing to add. OpenAI caches automatically for prompts at or above the minimum, with no marker and no code change, and charges no premium to write an entry (as of July 6, 2026, per the OpenAI guide). Cache hits require an exact prefix match, and the provider routes on a hash of the leading portion of the prompt — so your only job is Step 2: keep the stable content at the front. There is no marker to place.

Explicit caching — mark the boundary. Anthropic and Amazon Bedrock require you to mark where the cacheable prefix ends, and a write can be billed above the normal input rate.

  • Anthropic places a cache_control object on the content block at the boundary. The default entry lives five minutes; adding "ttl": "1h" requests a one-hour entry at a higher write rate. You may set up to four cache breakpoints in a request. As of July 6, 2026, per the prompt caching documentation:

    {
      "type": "text",
      "text": "<system prompt, tool definitions, repository context>",
      "cache_control": { "type": "ephemeral" }
    }
  • Amazon Bedrock uses a cachePoint marker in the Converse API, placed in the system, messages, or tools fields after the stable content; in the InvokeModel API for Claude models it uses the same cache_control object, and caching is on by default for InvokeModel. Checkpoints are processed toolssystemmessages, and changing an earlier section invalidates the later ones, so place stable sections first. As of July 6, 2026, per the Bedrock guide:

    "cachePoint": { "type": "default" }

Explicit caching with a separate cache object — Google Gemini. Gemini’s newer models cache implicitly by default, applying a discount when a prefix matches with no configuration. Its explicit mode is the odd one out: instead of a per-request marker, you create a cache object in its own API call, get back a handle, and reference that handle on later requests — closer to an “upload it first” model. As of July 6, 2026, see the context caching documentation.

The shape differs, but the procedure does not: you are always establishing a reusable prefix and then reusing it. Whatever provider you are on, the marker (or its absence) is not proof of anything. That is Step 3’s job.

Step 4: Verify the cache is being read

This is the step the marker does not do for you, and the one most guides skip. Adding a cache marker asks the provider to cache; it does not confirm the provider did, or that later requests are reusing what it stored. The response’s usage object answers that directly.

Send the same-prefix request twice. The first request writes the entry; the second should read it. On the second response, read the cache-read field:

  • Anthropiccache_read_input_tokens (tokens served from cache) and cache_creation_input_tokens (tokens written); input_tokens counts only the uncached remainder.
  • OpenAIcached_tokens, nested under usage.prompt_tokens_details.
  • Amazon BedrockcacheReadInputTokens and cacheWriteInputTokens; inputTokens counts only the non-cached remainder.
  • Google Gemini — the cached-content token count under usageMetadata (usage_metadata in the Python SDK).

A non-zero, growing cache-read count across repeated requests is the proof that caching engaged. Zero on the second request means it did not — and now you know before the bill arrives, not after. Read the write counter too: a non-zero write on the first request followed by a zero read on the second tells you the entry was stored but not matched, which points at a broken prefix rather than a below-minimum one.

Two panels of response usage objects. In the working panel, request one has a large cache-write count and zero reads, and request two has zero writes and a large cache-read count. In the broken panel, both requests show a cache write and zero reads, labelled a silent no-op.
Figure 3. Send the same-prefix request twice and read the response's cache-read counter. A working cache writes on the first request and reads on the second; a broken cache writes every time and never reads — a silent no-op you catch here, before the bill arrives.

Verification tells you the mechanism works. It does not tell you it is paying off.

Step 5: Measure the net saving

A cache that reads is not automatically a cache that saves. On an explicit provider you paid a premium to write the entry, and that premium has to be earned back by enough cheap reads before the entry’s TTL expires. Confirming a read (Step 4) and confirming a net saving (this step) are different checks, and it is possible to pass the first and fail the second — a prefix read only once or twice before it expires can cost more with caching than without.

You already have the inputs: the token counts from Step 4. To measure the saving over a reuse window, price what actually happened against what you would have paid with caching off, using multipliers relative to the normal input rate:

  • Caching path = (cache-write tokens × write multiplier) + (cache-read tokens × read multiplier) + (uncached tokens × 1).
  • No-caching path = (all input tokens × 1), for the same requests.

The multipliers are the provider’s, dated. As of July 6, 2026, Anthropic prices a five-minute cache write at 1.25× the input rate, a one-hour write at 2×, and a cache read at 0.1× (a tenth of input), per the prompt caching documentation; OpenAI charges no write premium and only discounts reads. Plug your own reported counts into both lines and the sign of the difference is your answer. As a worked shape on the coding agent: one write of a large prefix at 1.25× followed by many reads at 0.1× crosses below the all-input-rate line after the first couple of reads, and the gap widens with every further reuse — which is exactly the break-even curve the concept guide derives and measures in money. This guide keeps it in rate multipliers so the arithmetic is portable across models and dates.

Over time, two signals confirm the saving is holding without redoing the sum on every request: the cached-token share of your input rising toward the stable-prefix fraction you expect, and the cost-per-request falling at steady usage. If you enabled caching and neither moved, treat it as a Step 4 failure in disguise — the prefix is probably not matching.

When the counter stays at zero

If Step 4 returns zero reads, the loop closes back to Steps 1 and 2 — and almost always to one of three causes. Work them in order:

  1. The prefix is below the minimum. Check that the tokens ahead of your marker clear the model’s floor from Step 1. Below it, nothing is stored, so both the write and read counters stay at zero. Enlarge the stable prefix or confirm you are on the model whose floor you assumed.
  2. A volatile value is breaking the prefix. If the write counter is non-zero but the read counter is not, the entry is being stored and never matched. Diff the rendered bytes of two “identical” requests and look for a timestamp, id, per-user string, or reordered JSON near the front. Move it behind the boundary.
  3. Reuse is slower than the TTL. If both counters look healthy in a tight test but production shows few reads, your requests are arriving further apart than the entry lives, so it expires between calls. Cluster requests that share a prefix inside the TTL window, or where supported, request a longer TTL.

This is the “keep the prefix from breaking” step, and it is ongoing rather than one-time: a later change that injects a per-request value into the prefix will silently undo caching, and the only thing that catches it is the cache-read counter you now know how to read. Wire that counter into whatever you already watch, so a regression shows up as a metric, not a surprise on the invoice. When the counter is stuck and the three causes above don’t explain it, Why your prompt cache isn’t working is the full diagnostic reference — the same write / read / economics decision tree, with the read-side failure localized to the exact request segment that broke.

Where to watch it over time

Once caching is on and verified, the job shifts from enabling to monitoring — and the two signals that matter, cached-token share and cost-per-request, live inside each provider’s usage data. On a single provider you can read them from the usage object directly — on Claude, the Console’s Caching page charts cached-token share and write amortization for you (How to read Claude’s cache usage dashboard). Across several providers they are scattered across different billing surfaces with different field names, which is where pulling cached-versus-uncached usage into one place earns its keep; tracking AI costs across providers covers that, and CostCompass pulls usage from your connected providers into one running total so cached-token share and cost-per-request are visible when you look. Caching is also one lever among several — it composes with routing requests to cheaper models and centralizing policy through a gateway, both placed in context by The Hidden Economics of AI Coding.

The marker was never the hard part. Structure the prefix, enable it, confirm the read counter, measure the net, and keep the prefix from breaking — do those five things and caching stops being a hopeful toggle and becomes a cost lever you can prove.

Frequently asked questions

I added cache_control but cache_read_input_tokens is still zero. Why?
A zero read count means the provider never matched your prefix against a stored entry. Three causes account for almost all of it. First, the prefix is below the model's minimum cacheable size, so nothing was stored — check that the tokens before your breakpoint clear the model's floor (as of July 6, 2026, 1,024 tokens for Claude Opus 4.8 and Sonnet 5 on Anthropic's direct API, higher for some models). Second, a value near the front of the request changes on every call — a timestamp, a request id, a per-user string, or non-deterministic JSON key order — which resets the match; move anything volatile to the tail. Third, your reuse is slower than the cache's TTL, so the entry expires between calls and each request writes a fresh one. Confirm the first request wrote (a non-zero cache_creation_input_tokens) before assuming the read path is the problem.
What is the minimum number of tokens before prompt caching does anything?
There is a floor below which the provider stores nothing, and it depends on the model, not just the provider. As of July 6, 2026, Anthropic requires 1,024 tokens for Claude Opus 4.8 and Sonnet 5 and more for other models; OpenAI caches automatically for prompts of 1,024 tokens or longer; Amazon Bedrock's minimum is per-model per cache checkpoint (1,024 tokens for Claude 3.7 Sonnet, 4,096 for Claude Opus 4.5 and Sonnet 4.5); Google Gemini's minimum ranges from 2,048 to 4,096 tokens depending on the model. Below the floor your request still succeeds, but nothing is cached and no error is returned — so the only signal is a cache-read counter stuck at zero. Always check the current number against the provider's own documentation before you plan around it.
Do I need to change my code to get prompt caching on OpenAI?
No. OpenAI's prompt caching is automatic — it applies to requests of 1,024 tokens or longer with no marker, no parameter, and no extra fee to write an entry (as of July 6, 2026). That is the main split between providers. Anthropic and Amazon Bedrock use explicit caching, where you mark where the cacheable prefix ends and a cache write can be billed above the normal input rate. On an automatic provider your only job is to keep the stable content at the front of the request so the provider's prefix hash matches; on an explicit provider you also place the marker.
How do I make a cached prompt last longer than five minutes?
Where the provider supports it, you request a longer time to live (TTL) when you write the entry. On Anthropic and on Amazon Bedrock for supported models, add "ttl":"1h" to the cache control object to get a one-hour entry instead of the default five minutes (as of July 6, 2026); the longer entry is billed at a higher write rate. Whether the longer TTL is worth its higher write premium is an economics question, not a mechanics one — the companion guide on prompt caching walks through when a longer window pays for itself. If reuse is faster than five minutes, the default TTL already refreshes on each hit at no extra charge, so you usually do not need the longer window.
How do I know if prompt caching is actually saving money and not just working?
Those are two separate checks, and passing the first does not guarantee the second. A non-zero, growing cache-read counter proves the mechanism engaged — the provider stored your prefix and is reusing it. It does not prove the workload is net-cheaper, because on an explicit-caching provider the write premium you paid up front still has to be earned back by enough cheap reads before the entry expires. To measure the saving, take the reported cache-read and cache-write token counts, price the reads at the cache-read rate and the writes at the write-premium rate, and compare the total against pricing every token at the normal input rate over the same reuse window. Watch two signals over time — cached-token share rising toward the stable-prefix fraction you expect, and cost-per-request falling at steady usage.

About the author

Joubert Berger builds CostCompass, a spend-intelligence dashboard that pulls usage from AI and compute providers into one month-to-date total, a forecast, and a per-provider breakdown. This guide reflects how CostCompass reads each provider's own usage API — see the security model for how your keys are handled.

Watch your cached-token share, not just your token count

Once caching is on, the signals that tell you it is still working — cached-token share rising, cost-per-request falling — are scattered across each provider's billing surface. CostCompass pulls usage from your connected providers into one running total so you can see them when you look.