Skip to content

What a Migration Does to Existing Prompt Caching Cost Projections

10 min read · updated August 11, 2026

The saving on your caching slide is a single percentage, and it is a composite of four separate provider behaviours. A migration changes all four independently, which is why the number does not scale — it has to be rebuilt from the four inputs.

What the old estimate quietly assumed

A caching saving is almost always computed as: the fraction of input tokens that sit in a stable prefix, multiplied by one minus the discounted read rate. That formula has three unstated assumptions baked in. It assumes every eligible request actually caches; it assumes writing to the cache is free; and it assumes each cache entry is read many times before it expires, so the write cost amortises away.

None of the three is a property of your workload. All three are properties of the provider, and they are the first things to re-read when you change one. Treat every figure below as an input you substitute from your own contract and the current documentation, not as a number to quote.

Three rules that differ, and what each costs you

Whether caching is something you ask for. OpenAI documents prompt caching as automatic for eligible requests on supported models, with no code change required (OpenAI prompt caching guide). Anthropic’s is explicit: you mark a breakpoint with cache_control on a content block, with a documented maximum of four breakpoints per request (Anthropic prompt caching docs). Migrating from the explicit model to the automatic one and deleting the breakpoints is correct; migrating the other way and deleting nothing means you have shipped a system that caches nothing at all, while your projection still claims the saving.

The minimum cacheable prefix. OpenAI documents a strict minimum of 1,024 tokens on current models. Anthropic’s minimum is per-model and not monotonic across generations — its own documentation gives 512 tokens on the newest model, 1,024 on several others, and 2,048 or 4,096 on some. A prompt below the minimum does not error. It reports zero cache-creation tokens and is billed at the full rate, silently. Any request class whose prefix falls under the new minimum contributes exactly zero to the saving, and the old estimate counted it at the full discount.

Write and read multipliers. Both providers document a premium on the request that populates the cache and a discount on the ones that read it. Anthropic documents cache writes at 1.25× the base input rate for its default five-minute lifetime and 2× for the one-hour option, with reads at roughly 0.1×. OpenAI documents a 1.25× write on its newer models with reads billed at a reduced rate. Call the write multiplier w and the read multiplier r; those two letters are the only part of the pricing this page needs, and you fill them from the tables in force on your cutover day.

The arithmetic, with the inputs labelled

Take one stable prefix of P tokens and one cache lifetime. Assume — this is the assumption doing the work — that the prefix is written once and then read n times before the entry expires. Relative to the uncached cost of the same traffic, the ratio is:

uncached cost   = (n + 1) · P
cached cost     = w · P   +   n · r · P

ratio           = (w + n·r) / (n + 1)

break-even (ratio < 1)   ⇔   n > (w − 1) / (1 − r)

Substituting the two shapes above makes the point immediately. With a 1.25× write and a 0.1× read, break-even is at n > 0.28 — a single read pays for the write, and caching is close to free money. With a 2× write and a 0.2× read, break-even is at n > 1.25, so you need at least two reads per write before the longer lifetime is worth choosing. The savings ceiling as n grows large is just r, the read multiplier, which is why the percentage on the old slide was roughly “one minus the read discount” — it was the limit, quietly presented as the average.

The sensitivity that matters is therefore not in w or r. Those change the break-even by a fraction of a read. It is in n, which changes the answer between “we lose money on caching” and “we save nine tenths of our input spend”.

Reads per write is the term that moves

n is not something you choose. It falls out of two things: how long the provider keeps the entry, and how your traffic is spaced. Both providers expose a lifetime knob and they are not the same. Anthropic documents a five-minute default with a one-hour option carrying the higher write multiplier. OpenAI documents a prompt_cache_options.ttl of thirty minutes on its newer models, and on earlier ones a prompt_cache_retention choice between an in-memory window of a few minutes and a 24-hour option.

So the projection depends on a number you can compute from data you already have, without touching either provider. For each cache key — each distinct stable prefix — take the timestamps of the requests that used it over a representative day, compute the gaps between consecutive requests, and count how many gaps fall inside the candidate lifetime. Requests whose preceding gap exceeds the lifetime are writes; the rest are reads. That gives you n per key directly, and a weighted n across the workload.

This is the step that flips answers. A workload with a large shared system prompt and continuous traffic has a very large n and will save close to the ceiling under either provider. A workload with a per-tenant prefix and one request every twenty minutes has an n near zero under a five-minute lifetime and pays the write premium on nearly every call — caching makes it more expensive. The migration can move a workload from one regime to the other without changing a line of your code.

Replacing the projection with a measurement

Once traffic is on the new provider, stop projecting. Both APIs report per-request cache accounting, and the field names are not the same: Anthropic returns usage.cache_creation_input_tokens and usage.cache_read_input_tokens; OpenAI’s Chat Completions returns usage.prompt_tokens_details.cached_tokens, and its Responses API renames the same idea to usage.input_tokens_details.cached_tokens. A dashboard that keeps reading the Chat Completions path against the Responses API gets undefined, coerces it to zero, and reports a cache hit rate of zero percent on a system that is caching perfectly well.

Sum those fields over a day, divide by total input tokens, and you have the realised cached fraction. Multiply out with your own price table and you have the realised saving, which is the only number worth putting on a slide. If it is far below the projection, the first thing to check is not the price table but whether the prefix clears the minimum and whether something volatile — a timestamp, an unsorted serialisation, a per-request identifier — sits above the breakpoint and invalidates it on every call.

Multipliers, minimum prefix lengths and cache lifetimes are all published figures that vendors change. The formula above is stable; the inputs are not. Re-read both providers’ caching documentation on the day you set the threshold, and record the date next to the number.