Why your usage breakdown is mostly cache reads, what makes text reusable, how long it survives, and what silently breaks it.
cache_control. Saving costs 25% extra once; reading back costs 90% less, every time after.Jargon gets defined on first use, and there's a glossary at the end. If you haven't read the first document, the one thing you need from it is that the model processes text left to right and each position can only see what came before it.
Everything later depends on knowing the shape of what you send, so start there. A request to the API is a JSON document assembled from discrete pieces, each called a content block:
{
"tools": [ {tool definition}, {tool definition}, ... ], ← blocks
"system": [ {a chunk of instructions}, ... ], ← blocks
"messages": [
{"role":"user", "content":[ {text block} ]},
{"role":"assistant", "content":[ {text block}, {tool request} ]},
{"role":"user", "content":[ {tool result} ]},
...
]
}
A block is one indivisible item: a single tool definition, one chunk of system instructions, one message's text, one tool result, one image. A long conversation with tool use is easily a hundred blocks. The count matters later, so it's worth having the picture.
The server flattens all of this into one long sequence of tokens, in a fixed order: tools first, then system, then messages. That flattened sequence is what the model actually sees.
Two more terms, both used constantly below:
Both names are in common use and they mean different things:
| KV cache | prompt caching | |
|---|---|---|
| what it is | Key and value vectors held in GPU memory while one request runs | Processed prefix state kept between requests so it can be reused |
| lifetime | The request | 5 minutes, or 1 hour if you pay for it |
| you control it? | No — always on, invisible | Yes — via cache_control |
| on your bill? | No | Yes — two dedicated line items |
They rest on the same underlying fact, which is why the naming collides. The next two sections cover that fact; everything after is about the billed one.
Serving a request splits into two phases with quite different characteristics.
Prefill is processing your prompt. All its tokens go through all the layers together — large matrix multiplies, GPU saturated, limited by arithmetic throughput. Along the way, every token's key and value vector at every layer gets computed and held in memory. Prefill is what you wait through before the first output token appears.
Decode then produces output one token at a time. Each new token computes its own query, key and value, attends over all the stored keys and values from before, and appends its own. Only one token wide, so the multiplies are thin and the hardware spends most of its time moving memory rather than computing. Memory-bound rather than compute-bound — and that gap is roughly why output tokens are priced about five times input tokens.
The stored keys and values are the KV cache. Without it, generating token n would mean recomputing attention over all n−1 previous tokens from scratch: quadratic work instead of linear. It isn't optional, isn't configurable, and never appears on your bill.
Here is the load-bearing fact, and it follows directly from the causal mask in the first document:
So if two requests begin with byte-identical text, the processed state for that shared opening stretch is identical too — not similar, identical. It can be computed once, saved, and handed to the second request. The expensive prefill over that stretch never runs again.
That is prompt caching. Three consequences fall straight out, and between them they explain nearly every caching surprise:
Saving doesn't happen automatically. You mark a content block with cache_control, and the API saves the state of everything from the start of the prompt up to and including that block. That marker is called a cache breakpoint:
system=[
{"type": "text", "text": WHOLE_STYLE_GUIDE,
"cache_control": {"type": "ephemeral"}}, ← the breakpoint
]
("ephemeral" is currently the only type; it just means the entry expires rather than persisting.)
What gets stored is keyed by a hash of the whole prefix ending at that block. On a later request the API hashes the prefix at your breakpoint and looks for a stored entry with the same hash. Same hash means byte-identical opening text, which means the saved state is valid.
Three rules govern the rest, and misreading rule 2 is the usual cause of "I turned on caching and nothing happened":
Say your prompt has a large static system context in blocks 1–5, and block 6 holds a timestamp plus the user's message. You put the breakpoint on block 6, since it's last:
request 1 hash(blocks 1..6) saved ← the hash includes the timestamp
request 2 hash(blocks 1..6) is different → no match
step back: block 5, 4, 3, 2, 1
— but nothing was ever saved at those positions
result: full-price prefill, plus another useless save
You pay the 25% save premium on every single request and never once get a read. The backward search can't rescue you: it only finds things earlier requests saved, and saves only happen at breakpoints.
The fix is one line — move cache_control to block 5, the last block that stays identical across requests. Then every subsequent request matches on the first try.
You get four breakpoints, and they cost nothing — you're billed on tokens saved and tokens read, not on markers. Two reasons to use several: caching sections that change at different rates (tool definitions rarely, reference documents daily), and long conversations, where each turn appends blocks until your breakpoint drifts more than 20 blocks past the last save and the backward search can no longer reach it. A second breakpoint further back gives it something to find.
For a plain growing conversation, put cache_control at the top level of the request and the breakpoint advances by itself as turns accumulate:
response = client.messages.create(
model="claude-opus-5",
max_tokens=1024,
cache_control={"type": "ephemeral"}, # automatic placement
system=SYSTEM_PROMPT,
messages=history,
)
It puts the breakpoint on the last cacheable block — so it walks into exactly the trap above whenever your last block is the one that varies. Right default for a chat transcript; wrong for a prompt with a volatile tail.
Five minutes by default. Reading an entry resets that clock at no charge, so an active session stays warm indefinitely without ever paying a second save. The clock starts when the request that touches the entry begins, not when its response finishes — so a four-minute streaming response leaves only about a minute of usable life once it completes.
A 1-hour TTL is available as an explicit opt-in, and costs double base input on the save:
"cache_control": {"type": "ephemeral", "ttl": "1h"}
The break-even arithmetic is simple. A 5-minute save carries a 0.25× premium and each read saves 0.9×, so one read pays it back. A 1-hour save carries a 1.0× premium, so it needs two reads before it's ahead. If your calls come more often than every five minutes, the standard cache refreshes for free and the hour buys nothing. It earns its keep in the awkward zone — gaps longer than five minutes but shorter than an hour. A side-agent that runs for eight minutes; a user who steps away for coffee mid-conversation.
If you mix the two in one request, all 1-hour breakpoints must come before any 5-minute ones.
Three prices, all quoted per million tokens, all derived from the model's base input price:
The response reports three separate input counts, and the trap is that the one called input_tokens is not your total. It counts only the tokens after your last breakpoint.
cache_read_input_tokens tokens reused from a saved entry
cache_creation_input_tokens tokens saved to a new entry on this call
input_tokens tokens after the breakpoint, cached neither way
total input = the three added together
"usage": {
"cache_read_input_tokens": 29800, // reused, 0.1× price
"cache_creation_input_tokens": 240, // saved now, 1.25× price
"input_tokens": 62, // after breakpoint, full price
"output_tokens": 503
}
input_tokens looks impossibly small next to what you sent, that's the feature working. It also affects rate limits, since cache reads aren't counted against them.cache_creation_input_tokens and cache_read_input_tokens are both zero, no caching happened — and no error was raised. Usual causes: the prompt is below the minimum cacheable length, the cache_control field is missing, or something between you and the API stripped it. If you reach the API through a gateway or corporate proxy, this pair of fields is the cheapest possible test: send the same request twice a few seconds apart and check whether the second one reads.Below the threshold, cache_control is silently ignored. No error, no caching, no indication except those two zeroed counters.
| minimum | models |
|---|---|
| 512 | Opus 5, Fable 5 / 5.1, Mythos 5 / 5.1 |
| 1,024 | Opus 4.8, Opus 4.1, Opus 4, Sonnet 5, Sonnet 4.6, Sonnet 4.5, Sonnet 4 |
| 2,048 | Opus 4.7, Haiku 3.5, Mythos Preview |
| 4,096 | Opus 4.6, Opus 4.5, Haiku 4.5 |
If you're just short, padding the cached region up to the threshold is usually worth it — reads are cheap enough that crossing the line repays the extra tokens quickly.
Because the flattening order is tools, then system, then messages, a change at one level invalidates that level and everything after it. ✘ means the cache for that section is lost.
| change | tools | system | msgs | why |
|---|---|---|---|---|
| any tool definition | ✘ | ✘ | ✘ | tools come first, so editing one name or description invalidates the entire prompt |
| web search on/off | ✔ | ✘ | ✘ | quietly modifies the system prompt |
| citations on/off | ✔ | ✘ | ✘ | likewise |
tool_choice | ✔ | ✔ | ✘ | rendered into the message section only |
| adding or removing an image | ✔ | ✔ | ✘ | anywhere in the prompt, not just near the change |
| thinking configuration | model-specific | model-specific | ✘ | the mode and token budget get written into the prompt text |
| effort setting | model-specific | model-specific | ✘ | same mechanism; setting it explicitly to the default changes nothing |
If the first user request of the day shouldn't have to absorb the cold-prefill wait, you can pay for the save ahead of time using max_tokens: 0. The API reads the prompt, saves the entry, and returns immediately with an empty response and no output tokens billed.
client.messages.create(
model="claude-opus-5",
max_tokens=0,
system=[{"type": "text", "text": SYSTEM_PROMPT,
"cache_control": {"type": "ephemeral"}}],
messages=[{"role": "user", "content": "warmup"}],
)
Put the breakpoint on the shared opening, not on the placeholder message — otherwise the entry is keyed to the placeholder and your real traffic won't match it. This is also why automatic placement is wrong here. Match your thinking and effort settings to the real requests too, since those get written into the prompt. And the TTL still applies: re-warm inside the window, or buy the hour.
cache_control on the last block that's byte-identical across the requests meant to share a cache.cache_read_input_tokens on the second request. Both counters zero means caching never engaged.tool_choice, image presence, thinking config and effort constant across a session.| content block | One indivisible piece of a request: a tool definition, a chunk of system text, a message, a tool result, an image. |
| prefix | An opening stretch of the token sequence, counted from the very first token. |
| prefill | The phase that processes your prompt. Compute-bound; the wait before the first output token. |
| decode | The phase that generates output, one token at a time. Memory-bound. |
| KV cache | Keys and values held in GPU memory during one request. Automatic, unbilled. |
| prompt caching | Saving processed prefix state between requests. Billed, and under your control. |
| cache breakpoint | A cache_control marker on a block, saying "save everything up to here". |
| ephemeral | The only cache type. Means the entry expires rather than persisting. |
| TTL | Time-to-live: 5 minutes by default, 1 hour as a paid option. |
| cache write / save | Creating an entry. Costs 1.25× base input, once. |
| cache read / hit | Reusing an entry. Costs 0.1× base input, and refreshes the TTL for free. |
| lookback window | The 20 blocks the API steps back through searching for a previously saved entry. |
| pre-warming | Paying for a save in advance with max_tokens: 0, so real traffic starts warm. |
Prices and thresholds verified against Anthropic's documentation on 2 September 2026. They change; the mechanism doesn't.