Prompt Caching in the Claude API: A Production Guide

TL;DR
Cut Claude API spend by up to 90% with prompt caching. Real numbers, TypeScript SDK code, and the gotchas Anthropic's docs gloss over.
Last updated: October 18, 2026
Updated October 18, 2026: The code samples check out against @anthropic-ai/sdk 0.135.0, but several claims around them did not match Anthropic's prompt caching docs. 5-minute cache writes cost 1.25x base input, not nothing extra. Minimum cacheable lengths now vary from 512 to 4,096 tokens by model (Haiku 4.5 is 4,096, not 2,048). Caches are isolated per workspace on the Claude API, not shared across the whole organization. max_tokens does not affect the cache key, streaming cache stats arrive in message_start, and the 1-hour TTL pays off from the second call in an hour, not after about 12 reads. The sections and FAQ below are corrected.
Official Sources#
| Resource | Link |
|---|---|
| Prompt Caching Documentation | platform.claude.com/docs/en/build-with-claude/prompt-caching |
| Messages API Reference | docs.anthropic.com/en/api/messages |
| Anthropic SDK (TypeScript) | github.com/anthropics/anthropic-sdk-typescript |
| Anthropic Pricing | anthropic.com/pricing |
| Claude Models | docs.anthropic.com/en/docs/about-claude/models |
The 90% Discount Most Teams Are Leaving On The Table#
Every team I have looked at running Claude in production with a system prompt over 2k tokens is paying full freight on tokens they could be getting for a tenth of the price. Prompt caching has been generally available on the Anthropic API for over a year, and it is still the single biggest cost lever most apps have not pulled. Once you set it up correctly, cached input tokens cost about 10% of normal input tokens on read, and your time-to-first-token on a long-context call drops from seconds to a few hundred milliseconds.
This guide is the version of the docs I wish I had the first time I shipped a caching layer to production. We will cover what the cache actually does, when it pays off, the SDK code you should ship, the cache-invalidation footguns, and how to monitor hit rate so you actually realize the savings instead of assuming them.
We covered the basics in our Prompt Caching Explained video on YouTube. This post is the long-form, production-grade companion.
What Prompt Caching Actually Does#
Anthropic's prompt cache is a server-side, ephemeral cache keyed on the exact byte sequence of your prompt prefix. When you mark a block with cache_control: { type: "ephemeral" }, the API stores the model's internal state at that breakpoint. The next request that arrives within the TTL with the same prefix up to that breakpoint hits the cache.
There are two TTL options:
- 5-minute cache - default, writes cost 1.25x normal input, reads cost 0.1x
- 1-hour cache - writes cost 2x normal input, reads cost 0.1x
The read multiplier is lower on the newest models: Anthropic's pricing table lists 0.05x for Opus 5.5 and Sonnet 5.5 and 0.025x for Fable 5.1 and Mythos 5.1. A cache hit also refreshes the entry's lifetime at no extra cost.
Cache writes are slightly more expensive than a normal call. Cache reads are dramatically cheaper. The math is simple: if you reuse the same prefix more than once or twice within the TTL window, caching wins. If you do not, it loses.
What the docs do not loudly say:
- The cache is a prefix cache. It matches from the start of your messages array. Change a single token before a cache breakpoint and the entire downstream cache is invalidated.
- You get up to four cache breakpoints per request. Most apps need two: one after the system prompt, one after the static document context.
- Cache hits are not all-or-nothing. A request can hit the first breakpoint, miss the second, and you pay the cache-read price for the first chunk plus the cache-write price for the second.
- There is a minimum cacheable prompt length, and it depends on the model. Per Anthropic's docs it is 512 tokens for Opus 5.5, Sonnet 5.5, Haiku 5.5 and Fable 5; 1,024 for Sonnet 4.5, Sonnet 4.6, Sonnet 5 and Opus 4.8; 2,048 for Opus 4.7; and 4,096 for Haiku 4.5, Opus 4.5 and Opus 4.6. Cache a shorter prefix and you silently pay normal price.
When Caching Wins, And When It Is Just Overhead#
The break-even is roughly: if a prefix is reused more than once or twice within five minutes, cache it. If you are running Fable 5, the prompt caching economics on Fable 5 post works through this break-even at its specific cache-write and cache-hit rates. Specific scenarios where the ROI is obvious:
For the new small-model tier, keep the Claude Haiku 5.5 pricing cliff in mind: prompts that cross 100K tokens move into a higher price tier, so cache reads and context trimming matter even when the per-token sticker price looks tiny.
- Long system prompts and skills. Anything over 2k tokens that ships on every call.
- RAG with stable document context. Retrieved chunks that are the same across a multi-turn conversation.
- Multi-turn chat. The conversation history grows; the early turns are stable. Cache up to the last assistant turn.
- Batch document analysis. Same instructions, different documents. Cache the instructions.
- Agent loops. Tool definitions and the system prompt are identical across iterations.
Where caching is overhead:
- One-shot single-user queries where the prompt will not repeat.
- Highly dynamic prompts where every request changes the early tokens (e.g., putting a timestamp at the top of the system prompt - yes, people do this).
- Prompts below your model's minimum. Below the floor (512 to 4,096 tokens depending on the model), it is a no-op.
The TypeScript Code You Should Actually Ship#
Here is a minimal but production-shaped example using the official Anthropic SDK. It caches a long system prompt and a static knowledge-base block, leaving the user message uncached.
import Anthropic from "@anthropic-ai/sdk";
const client = new Anthropic();
const SYSTEM_PROMPT = `You are a senior support engineer for Acme Cloud.
Answer using only the provided knowledge base. Cite section IDs.
[... 3000 more tokens of policy, tone, and examples ...]`;
const KNOWLEDGE_BASE = await loadKnowledgeBase(); // ~15k tokens, stable per deploy
export async function answer(userMessage: string) {
const response = await client.messages.create({
model: "claude-sonnet-4-5",
max_tokens: 1024,
system: [
{
type: "text",
text: SYSTEM_PROMPT,
cache_control: { type: "ephemeral" },
},
{
type: "text",
text: KNOWLEDGE_BASE,
cache_control: { type: "ephemeral" },
},
],
messages: [{ role: "user", content: userMessage }],
});
// Inspect cache usage on every response
console.log({
cache_creation: response.usage.cache_creation_input_tokens,
cache_read: response.usage.cache_read_input_tokens,
input: response.usage.input_tokens,
output: response.usage.output_tokens,
});
return response;
}
Two breakpoints, two cache layers. The first request after a deploy pays the write cost on both blocks. Every subsequent request inside five minutes reads both at ~10% of input price.
For a multi-turn chat, you want a third breakpoint on the last assistant message so the growing conversation history caches as it goes:
const messages = history.map((m, i) => {
const isLastAssistant =
m.role === "assistant" && i === history.length - 1;
return {
role: m.role,
content: isLastAssistant
? [{ type: "text", text: m.content, cache_control: { type: "ephemeral" } }]
: m.content,
};
});
It keeps the rolling conversation cached without burning a breakpoint per turn. Anthropic now also offers automatic caching: put a single cache_control: { type: "ephemeral" } at the top level of the request and the API places the breakpoint on the last cacheable block and moves it forward as the conversation grows.
Production Gotchas We Have Hit#
1. Whitespace and JSON ordering. If your system prompt is built from a template that re-serializes a JSON object, key ordering can change between requests and silently kill the cache. Lock down your serializer or feed strings, not objects.
2. Timestamps in system prompts. "Today's date is 2026-04-29" at the top of the system prompt is a cache killer for every request from the next day onward. Move it into the user message or a separate uncached block at the end of the system array.
3. Tool definitions count as part of the prefix. If you reorder tools, you invalidate the cache. Sort tools deterministically.
4. The 5-minute TTL is rolling. Each cache hit refreshes the TTL. A high-traffic prompt stays warm forever. A low-traffic one dies between requests, and you pay write cost again. For prompts you call less than once every five minutes, the 1-hour TTL wins quickly: two calls in an hour cost 2x + 0.1x = 2.1x input with a 1-hour cache, against 1.25x + 1.25x = 2.5x with two 5-minute writes, and the gap widens with every extra call.
5. Streaming responses still report cache stats. Per Anthropic's docs, cache_creation_input_tokens and cache_read_input_tokens arrive in the message_start event's usage. Do not assume cached calls skip usage reporting.
6. Cache misses on "obviously identical" prompts. Usually one of: trailing whitespace, a Unicode normalization difference, a model version change, or a request setting that is rendered into the prompt. Anthropic's invalidation table lists tool definitions, tool_choice, images, the thinking configuration, output_config.effort and the fast-mode speed setting. max_tokens is not on that list.
Caching Inside RAG Pipelines#
The mistake teams make with RAG plus caching is caching the wrong thing. The retrieved chunks are usually the most dynamic part of the prompt. The instructions and tool list are the most static. Cache those.
A clean layering for a RAG agent:
- Layer 1 (rarely changes): system prompt, persona, tool definitions
- Layer 2 (changes per session): user profile, account context, project metadata
- Layer 3 (changes per query): retrieved chunks
- Layer 4 (uncached): the user message itself
You get two breakpoints on Layer 1 and Layer 2. Layer 3 is fresh per query, no breakpoint. Layer 4 is just the user message. This pattern routinely takes a 25k-token RAG call from $0.075 input cost to about $0.012 on cache hits, with sub-second time-to-first-token.
Monitoring Cache Hit Rate, Or You Did Not Actually Save Anything#
The most common failure mode is shipping caching, declaring victory, and never noticing your hit rate is 30% because some request path is breaking the prefix. You need observability from day one. Every response includes usage.cache_creation_input_tokens and usage.cache_read_input_tokens - log both, then aggregate.
A useful metric is cache hit ratio:
hit_ratio = cache_read_tokens / (cache_read_tokens + cache_creation_tokens + uncached_input_tokens)
A healthy production prompt should sit above 0.85. Below 0.6, something is breaking the prefix and you should investigate. We built CodeBurn specifically to surface this metric across runs, and the same pattern works inside any FinOps dashboard you already have. The 400-Dollar Overnight Bill post-mortem walks through what happens when you do not.
Set an alert when hit ratio drops below a threshold for any prompt template. Almost every cache regression we have shipped was caught this way: a deploy added a new dynamic field to the system prompt, and the alert fired within an hour.
Scaling To Multi-User, Multi-Agent Systems#
The cache is not per-user. On the Claude API, caches are isolated per workspace (Bedrock and Google Cloud isolate per organization), so two users whose requests run in the same workspace and send the same prompt prefix share the cache. This is great for shared system prompts and tool definitions. It is dangerous for anything that should be user-isolated.
Concrete patterns:
- Shared layer first, user layer second. Put the org-wide system prompt in the first cache block, the per-user context in the second. The first block has a much higher hit rate across all users.
- Per-agent prompts in agent swarms. If you run N agents with different system prompts, each one gets its own cache. Keep prompts deterministic across agent restarts.
- Concurrent requests do not collide. The API writes the cache once the first response begins, so two requests with the same prefix arriving at the same time both pay the write cost, then later requests read. There is no thundering-herd protection. For very high-traffic prompts, a warm-up call on deploy is cheap insurance; Anthropic documents a pre-warming request with
max_tokens: 0for exactly this.
Production Checklist Before You Ship#
- Cached prefix above your model's minimum length, marked with
cache_control - Static knowledge / tool definitions in a second cache block
- No timestamps, request IDs, or non-deterministic content above any cache breakpoint
- Tool list sorted deterministically
- Cache hit ratio logged to metrics
- Alert configured for hit ratio below 0.6
- Decided 5-minute vs 1-hour TTL based on call frequency
- Tested cache stats on a smoke-test request after every deploy
Prompt caching is the closest thing to a free lunch in the Claude API. It is also the easiest optimization to ship broken and never notice. Get the breakpoints right, monitor the hit ratio, and you will pay roughly an order of magnitude less for the same workload.
For more on optimizing Claude in production, see our writeups on tool use patterns and building MCP servers.
FAQ#
How much does Claude prompt caching actually save?#
Cached input tokens cost approximately 10% of the normal input token price when read from cache. For a typical production workload with a 15k-token system prompt that achieves an 85%+ cache hit rate, you can expect to save 70-90% on input token costs for those cached portions. The exact savings depend on your hit rate, prompt size, and whether you use the 5-minute or 1-hour TTL option.
What is the minimum token count for prompt caching to work?#
It depends on the model. Per Anthropic's docs, the minimum cacheable prompt length is 512 tokens for Opus 5.5, Sonnet 5.5, Haiku 5.5 and Fable 5; 1,024 for Sonnet 4.5, Sonnet 4.6, Sonnet 5 and Opus 4.8; 2,048 for Opus 4.7; and 4,096 for Haiku 4.5, Opus 4.5 and Opus 4.6. Below the threshold, the cache control annotation is silently ignored and you pay full price. This is why caching is most effective for longer system prompts, knowledge bases, and tool definitions.
Why is my cache hit rate low even with caching enabled?#
The most common causes of low cache hit rates are: timestamps or request IDs appearing before cache breakpoints, non-deterministic JSON serialization changing key order between requests, trailing whitespace differences, tool definitions being reordered between calls, or Unicode normalization differences. The cache key is an exact byte-sequence match, so even invisible differences invalidate the cache. Log cache_creation_input_tokens and cache_read_input_tokens on every response to diagnose.
How many cache breakpoints can I use per request?#
You can use up to four cache breakpoints per request. Most production applications need two: one after the system prompt and one after static document context or tool definitions. For multi-turn chat, a third breakpoint on the last assistant message lets the conversation history cache as it grows. Cache hits are not all-or-nothing - a request can hit the first breakpoint, miss the second, and you pay read price for the first chunk plus write price for the second.
Should I use the 5-minute or 1-hour TTL for prompt caching?#
Use the 5-minute TTL (default) for high-traffic prompts called more than once per 5 minutes; its writes cost 1.25x normal input. Use the 1-hour TTL for lower-traffic prompts - writes cost 2x normal input and reads still cost 0.1x on most models. If calls are more than five minutes apart, the 1-hour TTL already wins at two calls an hour (2.1x versus 2.5x input). The 5-minute TTL is rolling and refreshes on each hit, so consistently accessed prompts stay warm indefinitely.
Does prompt caching work with streaming responses?#
Yes. Streaming responses report cache statistics in the message_start event's usage, with the same cache_creation_input_tokens and cache_read_input_tokens fields as non-streaming calls. The cost savings are identical regardless of whether you stream the output.
Is the prompt cache shared across users in my application?#
Yes, within a workspace. On the Claude API, caches are isolated per workspace (per organization on Bedrock and Google Cloud), not per user or per request. Two different users whose requests run in the same workspace and hit the same prompt prefix share the cache, which is excellent for maximizing hit rates on shared system prompts and tool definitions. For multi-tenant applications, put the org-wide system prompt in the first cache block and per-user context in the second - the shared layer achieves a much higher hit rate across all users.
How do I know if prompt caching is actually working?#
Monitor the usage.cache_creation_input_tokens and usage.cache_read_input_tokens fields returned in every API response. Calculate your cache hit ratio as cache_read_tokens / (cache_read_tokens + cache_creation_tokens + uncached_input_tokens). A healthy production prompt should have a hit ratio above 0.85. Set an alert for when hit ratio drops below 0.6 to catch regressions early. The first request after a deploy or cache expiry will show cache creation tokens; subsequent requests within the TTL should show cache read tokens.
Continue Reading#
- Claude Code Idle Compaction: What It Does and How to Turn It Off - the Claude Code feature that compacts before the 1-hour cache expires
- Claude Haiku 5.5 Developer Guide - cache read at $0.01 per million and the 100K price tier
- Context Engineering for Agents: Caching, Compaction, Subagents - caching as one of five levers for keeping agent context small
- Prompt Caching Across AI Providers: Prices, TTLs and Setup - how OpenAI, Gemini, DeepSeek, Mistral, xAI and Qwen compare with Claude on write fees, read rates and TTLs
- Claude Code Prompt Cache: Read the Hit Ratio and Set 5m or 1h TTLs - the /usage cache line, status line fields and TTL settings
- Claude API Inline Tool Definitions: Add Tools Mid-Conversation - add or change tools without breaking the cached prefix
- Claude - the model family, pricing, and limits on one page
- Claude Agent SDK - pricing, features, and alternatives on one page
Get the next deep dive like this in your inbox
One email a week on Claude API and the rest of the AI dev stack. Free.
Read next
Prompt Caching Economics on Fable 5: When the 5-Minute TTL Pays
Fable 5 prompt caching economics: cache-write vs cache-read pricing, 5-minute vs 1-hour TTL break-even math, and worked agent-loop examples.
10 min readClaude Batch API: Cutting Async Workload Costs In Half
How to ship Claude's Batch API in production. 50% cost savings, TypeScript SDK code, JSONL request format, and the async architecture gotchas that bite at 100k requests.
11 min readExtended Thinking in Claude: When Deep Reasoning Pays For Itself
A production guide to Claude's extended thinking mode. Real cost math, TypeScript SDK code, and the tasks where reasoning tokens are worth 3x the spend.
12 min readNew here? Start with
Technical content at the intersection of AI and development. Building with AI agents, Claude Code, and modern dev tools - then showing you exactly how it works.








