← Blog

Claude prompt caching: the break-even math and the mistake that turns it off

Claude cache reads bill at a tenth of the input rate; writes cost 1.25x. The break-even math, the 5-minute TTL, and the mistake that disables caching.

Prompt caching is the biggest cost lever most Claude apps leave on the table — and the only one that can also make your bill worse. The pricing has a shape people miss: cache reads are cheap, but cache writes carry a surcharge. If you cache things that never get re-read, you are paying extra for the privilege.

Here is the actual math, using the numbers my metering layer bills against.

The four line items on every request

Every Claude request can produce up to four token counts, each at a different rate. This is the pricing function from my model registry — the same one the dashboard, quotas, and billing all read:

/**
 * Cost of a single request in USD.
 * Cache reads bill at ~0.1x the input rate; cache writes at 1.25x (5-minute TTL).
 */
export function costUsd(model: ModelId, usage: TokenUsage): number {
  const m = MODELS[model];
  return (
    (usage.inputTokens * m.inputPerMTok +
      usage.outputTokens * m.outputPerMTok +
      usage.cacheReadTokens * m.inputPerMTok * 0.1 +
      usage.cacheCreationTokens * m.inputPerMTok * 1.25) /
    1_000_000
  );
}

Two things to internalize:

  • Reads are a 90% discount. A cached token bills at roughly a tenth of the normal input rate.
  • Writes are a 25% surcharge. The first time a prefix is cached, those tokens cost 1.25x normal input. Caching is an investment, and investments can lose.

Break-even: one re-read pays for the write

Take a 2,000-token system prompt on Claude Opus 4.8 (5 dollars per million input tokens):

  • Uncached, that prefix costs 1.0 cent per request.
  • Writing it to the cache costs 1.25 cents — once.
  • Each subsequent read costs 0.1 cents.

So for N requests inside the cache window: uncached spend is 1.0N cents, cached spend is 1.25 + 0.1(N-1). At N=1 you lost a quarter of a cent. At N=2 you are already 33% ahead. By N=10 the prefix costs 2.15 cents instead of 10.

The general rule falls out of the multipliers: the write premium is 0.25x, each re-read saves 0.9x — so a single re-read within the TTL pays for the write three times over. In a chat product, where every turn resends the same system prompt and history prefix, that condition is nearly always met. Caching a one-off batch job that never repeats a prefix, though, is a pure 25% surcharge.

The mistake: one dynamic value at the top

Cache matching is a byte-exact prefix match. A single dynamic value early in your system prompt — a timestamp, a request ID, a "today is Wednesday" — changes the bytes, misses the cache, and triggers a fresh 1.25x write on every single request. That is the worst configuration available: you pay the write surcharge every time and never collect a read.

This is why my prompt registry keeps system prompts deterministic, with a comment that has survived every refactor:

/**
 * Keep system prompts deterministic (no timestamps, no per-request IDs):
 * prompt caching is a byte-exact prefix match, and a single dynamic value at
 * the top of the prompt disables caching for everything after it.
 */

Anything per-request — the user name, the date, retrieved context — belongs after the stable prefix, or in the user message, never at the top of the system prompt.

If you cannot see the hit rate, assume zero

My usage table records cache reads and writes as their own columns on every request, because the failure mode here is silent: nothing breaks when caching stops working, the bill just quietly grows. If cache reads are near zero in production while writes keep happening, a dynamic byte crept into your prefix and nobody noticed.

You can watch this live in the demo chat — the under-the-hood panel prints each request with cache reads at 0.1x and writes at 1.25x as separate line items, next to the exact cost. The same discipline as aborting streams when the client disconnects: measure the money path first, then the savings become visible instead of theoretical.

Things that bite

  • The TTL is five minutes. Caching pays inside active sessions and bursty traffic; a user who returns after lunch starts with a fresh write. Do not model savings off your total request count — model them off requests that arrive within minutes of each other.
  • Writes without reads are a surcharge, not a win. Audit any endpoint that caches but rarely repeats a prefix.
  • Very short prompts may not cache at all. Models enforce a minimum cacheable prefix length; below it, your cache_control marker is silently ignored. Check the current provider docs for the threshold rather than assuming.
  • The ratios hold across models, the absolutes do not. On Haiku the same 2,000-token prefix costs 0.2 cents uncached — caching still helps, but the cents at stake are 5x smaller than on Opus. Spend optimization effort where the tokens are expensive.

Shipwright — the Next.js starter kit this blog documents — ships this whole loop wired together: deterministic versioned prompts, cache-aware cost attribution per request in integer micro-USD, and a live panel that shows the math on every message.

Shipwright is a Next.js 16 + Claude starter kit that ships these patterns already done.

Try the live demo →