How Prompt Caching Cuts Your AI Bill ~90% (and the Floor Trap)

June 23, 2026 · updated June 25, 2026 · How Claude Actually Works (part 21)

▶ Watch on YouTube & subscribe to The Stack Underflow

If you send the same big chunk of context on every API call — a long system prompt, a set of tool definitions, a knowledge base — you’re paying full input token price to re-process identical text on every single request. The model doesn’t remember previous calls. From its perspective, that 10,000-token system prompt is brand-new on call 1, call 100, and call 10,000.

Prompt caching is Anthropic’s fix for that waste: mark the stable portion of your prompt with a single cache_control field, and the API stores the processed prefix server-side. Subsequent calls that match that prefix byte-for-byte pay about 10% of normal input price instead of 100%. Used correctly, it’s the highest-leverage cost lever available to you — but there’s a floor trap that causes the feature to silently no-op while your code exits clean and your bill stays exactly as high as before.

The one-sentence version: Prompt caching stores a stable prompt prefix so subsequent calls pay ~10% of input price instead of 100% — but there is a per-model minimum size, a short expiry window, and a write premium on the first call, so it only pays off when you reuse the same prefix soon and often.

The mechanism: prefix identity and the breakpoint

The core rule is strict: caching applies to an exact prefix match. Every byte before the cache breakpoint must be identical to what was cached. A single character difference anywhere in the prefix — a changed timestamp, a reordered tool, an updated instruction — misses the cache entirely and forces a full re-write.

┌──────────────── cached prefix (stable) ───────────────┐ ┌─── varies ───┐
[ system prompt ][ tool definitions ][ reference docs   ] [ user message ]

                                               cache_control breakpoint
                                               {"type": "ephemeral"}

The practical implication: structure your prompt so that everything stable comes first and everything dynamic comes last. If a user’s query appears before your tool definitions, the tool definitions are never in the prefix and can never be cached.

You can place up to four explicit breakpoints per request. This lets you cache at multiple granularities — for example, a 5-minute breakpoint on your system prompt and a 1-hour breakpoint on a large reference document that changes less frequently. A fifth breakpoint is added automatically by the API for conversational workloads.

Call 1 writes, call 2 reads

There are two distinct operations, each with its own cost and its own counter in the API response:

Call 1 (cache miss → writes the cache):
  usage.cache_creation_input_tokens  > 0   ← you paid 1.25x for this
  usage.cache_read_input_tokens      = 0

Call 2+ (cache hit → reads from cache):
  usage.cache_creation_input_tokens  = 0
  usage.cache_read_input_tokens      > 0   ← you pay 0.1x for this

The write is slightly more expensive than a normal input call — 1.25x for the default 5-minute TTL. The read is dramatically cheaper — 0.1x. The math: one write plus one read already saves money compared to two uncached calls. Every additional read compounds the saving.

A clean exit code is not a cache hit. If both counters are 0 after a cache_control call, the cache silently no-opped — most likely because the prefix fell below the model’s floor (see next section). Your code will not error. This is the trap.

The floor table: where the silent no-op lives

Each model has a minimum cacheable prefix length. Prefix the breakpoint with fewer tokens than the floor, and the cache does nothing — no error, no warning, both counters at zero.

The floors are not uniform and they have changed as the model lineup has expanded. As of June 2026 (verify against the Anthropic pricing docs before pinning these numbers):

ModelMin cacheable tokensNotes
Claude Fable 5 (claude-fable-5)512New frontier model, lowest floor
Claude Mythos 5 (claude-mythos-5)512Invitation-only (Project Glasswing)
Claude Opus 4.8 (claude-opus-4-8)1,024Current flagship Opus
Claude Opus 4.7 (claude-opus-4-7)2,048Legacy
Claude Opus 4.6 / 4.54,096Legacy; 4x higher than Opus 4.8
Claude Sonnet 4.6 (claude-sonnet-4-6)1,024Current speed/intelligence balance
Claude Sonnet 4.51,024Legacy
Claude Haiku 4.5 (claude-haiku-4-5)4,096Fastest; highest floor of current trio

The floor trap bites hardest when you port a working demo between models. A 2,000-token system prompt caches fine on Opus 4.8 (floor 1,024) or Sonnet 4.6 (floor 1,024), then silently fails on Haiku 4.5 (floor 4,096) — and on legacy Opus 4.6/4.5 (also 4,096). The classic break: a Sonnet prototype migrated to Haiku for cost, where the “working” caching setup now does nothing.

Practical rule: target 25% above the floor. For Haiku 4.5, that means your cached prefix should be at least ~5,100 tokens before you expect a hit.

Pricing: the real numbers

Multipliers are relative to the base input price for each model. The 0.1x read multiplier is what produces the “~90% savings” headline. (Prices current as of June 2026 — always verify at docs.anthropic.com/en/docs/about-claude/pricing.)

OperationMultiplierOpus 4.8 example (per MTok)Sonnet 4.6 (per MTok)Haiku 4.5 (per MTok)
Base input1.0x$5.00$3.00$1.00
5-min cache write1.25x$6.25$3.75$1.25
1-hr cache write2.0x$10.00$6.00$2.00
Cache read0.1x$0.50$0.30$0.10
Outputvaries$25.00$15.00$5.00

A concrete example: you have a 20,000-token system prompt on Sonnet 4.6. Without caching: $0.060 per call. With caching (after the first write): $0.006 per call on the cached prefix. At 1,000 calls per day, that’s $54 saved daily — on one prefix alone.

The expiry trap: TTL and when it bites you

The default TTL (time to live) for a cache entry is approximately 5 minutes, automatically refreshed each time it is read. A 1-hour TTL is available by passing "ttl": "1h" in the cache_control field — at 2x the write cost instead of 1.25x.

5-minute TTL (default):
  {"cache_control": {"type": "ephemeral"}}

1-hour TTL (extended):
  {"cache_control": {"type": "ephemeral", "ttl": "1h"}}

The expiry trap: if your calls are spaced further apart than the TTL, the cache expires between calls and you pay the write premium every time without collecting any reads. Caching helps bursty, frequent traffic. It actively hurts slow, intermittent traffic.

Scenario A — bursty (caching wins):
  t=0:00  Call → cache WRITE  (1.25x)
  t=0:01  Call → cache READ   (0.1x) ✓
  t=0:02  Call → cache READ   (0.1x) ✓
  t=0:03  Call → cache READ   (0.1x) ✓  ← also refreshes TTL

Scenario B — sparse (caching loses):
  t=0:00  Call → cache WRITE  (1.25x)
  t=0:10  Cache expires
  t=0:10  Call → cache WRITE  (1.25x) ← paying premium again, zero reads
  t=0:20  Cache expires again
  t=0:20  Call → cache WRITE  (1.25x) ← and again

Also worth knowing: since February 5, 2026, cache entries are isolated at the workspace level on the Claude API (not org-level). If you share an organization but use different API keys in different workspaces, each workspace has its own cache — a write in workspace A does not warm the cache for workspace B. Bedrock and Vertex AI maintain organization-level isolation.

How to apply this in production

Checklist before deploying prompt caching:

1. Measure your current prefix size in tokens.
   Use usage.input_tokens from a dry run — or the Tokenizer API.

2. Check the floor for your target model (table above).
   Is your prefix 25%+ above the floor? If not, either:
     a) Grow the prefix (add more stable context), or
     b) Switch to a model with a lower floor.

3. Structure the prompt: stable content first, dynamic content last.
   Order: system prompt → tool definitions → reference docs → user message.
   One changed byte anywhere in the prefix busts the whole cache.

4. After your first live call, read the usage counters — not the exit code.
   cache_creation_input_tokens > 0  → write confirmed
   cache_read_input_tokens > 0      → hit confirmed
   Both = 0 with cache_control set  → silent no-op, debug the floor

5. Choose TTL based on your call frequency.
   Calls closer than 5 min apart → default TTL (1.25x write, cheaper)
   Calls spaced 5–60 min apart  → 1-hour TTL (2x write, still worth it)
   Calls more than 1 hr apart   → consider whether caching helps at all

When caching pays off vs. when it doesn’t

SituationCaching verdict
Same 15K system prompt, hundreds of calls per hourBig win — high reuse, above every floor
Multi-turn Q&A on a large document in one sessionBig win — same document prefix, many questions
Tool-heavy agent with static tool definitionsWin on the tool definition block
Single one-off call with unique contextLoss — you pay the write premium and read it zero times
Calls spaced 10+ minutes apart (cache expires)Loss — constant re-writes, no reads
Prefix under the model’s floor (e.g., 3K tokens on Haiku 4.5)Silent no-op — neither win nor loss, just wasted cache_control field
Context that changes completely on every callInapplicable — nothing stable to cache

Common misconceptions

“Cached tokens are free.” Cache reads cost 0.1x of base input price — not zero. Ten percent of a gigantic prefix is still real money. Caching makes repeated context dramatically cheaper; it does not make it free. Do not treat it as a license to inflate your context window carelessly.

“Just add cache_control everywhere and you’re done.” The feature only helps when a stable prefix is reused within the TTL, by the same workspace, above the floor. Scattering breakpoints through a highly dynamic prompt saves nothing and slightly increases write costs.

“Prompt order doesn’t matter once caching is on.” It’s the whole game. The prefix must be byte-for-byte identical to hit the cache. A system prompt change, a reordered tool definition, or even a different timestamp in a header block busts the cache completely.

“A clean run means caching worked.” This is the most dangerous misconception. If both counters (cache_creation_input_tokens and cache_read_input_tokens) are 0 after a call with cache_control set, the API silently no-opped — almost certainly because the prefix was below the model’s floor. Your integration shows no error, the model produces normal output, and the bill is exactly as high as without caching.

Frequently asked questions

What exactly can I cache? Any stable prompt prefix — system prompt text, tool definitions, large reference documents, few-shot examples — as long as it is byte-for-byte identical across calls, it exceeds the model’s minimum token floor, and it appears before the variable content in your message structure.

How do I verify caching is actually working? Read the usage object in the API response. On the first call, cache_creation_input_tokens should be greater than 0. On subsequent calls, cache_read_input_tokens should be greater than 0. If both are 0 after you’ve added cache_control, debug the floor: print your prefix token count and compare it to the model’s minimum. A clean exit code tells you nothing about whether the cache fired.

Why did my savings disappear after I switched models? Almost certainly a floor mismatch. A prefix that sat above Sonnet 4.6’s 1,024-token floor may sit below Haiku 4.5’s 4,096-token floor. The code runs identically, the output looks identical, but the cache silently no-ops on the new model. Check the floor table against your actual prefix size.

Can I cache in a multi-turn conversation? Yes — and the API helps you here with automatic caching. Pass cache_control at the top level and the breakpoint automatically moves to the last cacheable block in the conversation. This is the recommended approach for chatbot-style workloads. For fine-grained control over multiple independently updated sections (tools, documents, history), use up to four explicit breakpoints placed at each section boundary.

Does caching work across users or just within one session? Cache entries are workspace-scoped (on the Claude API as of February 2026). Any request in the same workspace that sends the exact same prefix will hit the cache — it does not need to be the same user or session. This is a significant benefit for multi-user applications sharing a common system prompt: one warm cache serves all users in that workspace.

What happens when the cache expires during active use? If a read arrives after the TTL, the entry has expired. The API performs a full re-write, cache_creation_input_tokens lights up again, and the 5-minute (or 1-hour) clock resets. Each read refreshes the TTL, so a steady stream of requests keeps the cache alive indefinitely. The expiry only bites when there’s a gap longer than the TTL between calls.

Where this fits in the series

This tutorial is part of the cost and reliability stretch of How Claude Actually Works — the episodes that bridge from understanding the mechanics to running Claude affordably at scale. If you haven’t read the token pricing fundamentals yet, How LLM Tokens Work and Your AI Bill is the direct prerequisite — caching only makes sense once you understand what you’re paying per input token. For the broader picture of context management (not just caching, but pinning, summarizing, pruning, and compacting), the next episode Context Engineering: Pin, Summarize, Prune, Compact builds directly on this one. And to see how prompt caching fits into the full cost profile of a production system, Where Your AI Tokens and Dollars Go maps every line item. Browse all tutorials to follow the full series.


Sources: Anthropic prompt caching docs · Anthropic model overview · Anthropic pricing — verified June 2026.

Found this useful? The deep version lives on YouTube — new breakdowns of how AI dev tools actually work, weekly.

Subscribe on YouTube →