Figures on this page were verified 31 August 2026 against the providers' own documentation. Pricing, context windows and rate limits change without notice, so confirm any number against the provider before you rely on it. Tell us if something here is out of date.
Prompt caching charges repeated input at a fraction of the normal rate, and for any workload with a long fixed system prompt it is the single largest cost reduction available. On Anthropic, cache reads cost 10% of the base input price. The catch is that caching keys on an exact prefix, so one variable character in the wrong place silently disables it.
How the discount works
You mark a stable block of the prompt as cacheable. The first request pays a write cost. Subsequent requests beginning with a byte-identical prefix pay the much lower read rate for that portion, and full price only for what follows it.
Worked example: a 20,000-token system prompt with tool definitions, on Claude Sonnet 5 at $2 per million input tokens, called 10,000 times in a month.
| Scenario | Per call | 10,000 calls |
|---|---|---|
| No caching, 20K tokens at $2/M | $0.040 | $400 |
| Cache reads at 10% of base | $0.004 | $40 |
| Saving on the cached portion | $0.036 | $360 |
The mistake that silently disables it
Caching matches on an exact prefix. If anything near the top of your prompt varies per request, every request is a miss and you pay full price while your configuration and your dashboard both report that caching is enabled.
# WRONG: the timestamp changes every call, so nothing ever matches
system = f"Today is {now()}.nn{LONG_STABLE_INSTRUCTIONS}"
# RIGHT: stable block first, volatile content after the cache boundary
system = [
{"type": "text", "text": LONG_STABLE_INSTRUCTIONS,
"cache_control": {"type": "ephemeral"}},
{"type": "text", "text": f"Today is {now()}."},
]The usual culprits are a timestamp, a session or request ID, a user name, a randomised greeting, and retrieved documents placed above the instructions rather than below them. Order the prompt from most stable to most variable and the problem disappears.
When caching does not pay
- Short prompts. There is a minimum cacheable length, and below it the write overhead outweighs the saving.
- Genuinely unique requests. One-shot classification with no shared preamble has no prefix to reuse.
- Low frequency. Cache entries expire. If your traffic is slower than the lifetime, most calls pay a write and never get a read.
- Output-heavy work. Caching only discounts input. If your bill is dominated by generated tokens it will barely move, and capping
max_tokensis the lever instead.
Verify it is actually working
Do not assume. The API reports cache usage on every response, so assert on it rather than trusting configuration.
u = response.usage
print("written:", u.cache_creation_input_tokens)
print("read: ", u.cache_read_input_tokens)
print("full: ", u.input_tokens)
# In steady state reads should dominate. If they are always zero,
# something above the cache boundary is changing between calls.Log the read-to-write ratio as a metric. A sudden collapse is the earliest signal that someone has added a variable to the top of a system prompt, and it shows up days before anyone reads the invoice. To model what this is worth on your own volumes, use the API cost calculator, and see what actually drives your bill for the other three levers.
Frequently asked questions
How much does prompt caching actually save?
Cache reads cost 10% of the base input price on Anthropic. On a 20,000-token system prompt called 10,000 times a month at Sonnet 5 rates, that is roughly $400 down to $40 on the cached portion alone.
Why is my caching not working?
Almost always something variable near the top of the prompt. Caching matches an exact prefix, so a timestamp, session ID or user name at the start makes every request a miss while your configuration still says caching is enabled. Put volatile content last.
How do I confirm caching is active?
Read cache_read_input_tokens and cache_creation_input_tokens from the usage object on every response. In steady state reads should dominate. Log the ratio as a metric, because a collapse shows up days before the invoice does.



