fewer tokens, faster answers, a smaller bill
Anyone who sends the same long system prompt, the same documentation or the same codebase to Claude in full on every single request pays for identical tokens over and over again. Prompt caching keeps these recurring parts available server side and noticeably lowers both cost and latency once the caching strategy is built correctly.
Table of Contents
- 1. Why prompt caching is a cost lever
- 2. How prompt caching works technically in Claude
- 3. Placing cache breakpoints correctly
- 4. TTL choice: 5 minutes or 1 hour
- 5. Typical use cases with high savings potential
- 6. Prompt caching in agentic workflows
- 7. Measuring and monitoring cache hit rate
- 8. Pitfalls: when caching does not kick in
- 9. Cost model comparison
- 10. Summary
- 11. FAQ
1. Why prompt caching is a cost lever
Many applications built with Claude send the same large, static context along with every single request: a lengthy system prompt, a complete API documentation, an entire codebase or an extensive rule set. Without prompt caching, this context is fully reprocessed and fully billed on every request, even though the content has not changed between two requests.
Prompt caching solves exactly this problem: static parts of a prompt are kept server side for a limited time, so subsequent requests with an identical prefix only pay the full price for the new, variable parts. The reused portion is billed at a fraction of the regular input cost. For applications with long, recurring contexts, this saving adds up over thousands of requests to a substantial amount.
This article shows how prompt caching works technically in the Claude API, where cache breakpoints are sensibly placed, which TTL strategy fits which use case, and how to actually measure the real cost savings in practice instead of merely assuming them.
2. How prompt caching works technically in Claude
Technically, prompt caching is based on the principle that a certain conversation prefix, marked by a cache breakpoint, is stored server side as a processed state. When a subsequent request arrives with exactly the same prefix, Claude does not need to fully reprocess this part but instead falls back on the cached state. This significantly reduces both the latency until the first answer and the billed input tokens for the cached portion.
It is important to understand that prompt caching relies on exact prefix matching. Any change, even just an added space, before a cache breakpoint invalidates the cache for that section. The order within the prompt is therefore decisive: static parts such as the system prompt, tool definitions and long reference documents must consistently come before variable parts such as the actual user request.
import anthropic
client = anthropic.Anthropic()
response = client.messages.create(
model="claude-sonnet-4-5",
max_tokens=1024,
system=[
{
"type": "text",
"text": large_system_prompt, # long, static instructions
"cache_control": {"type": "ephemeral"} # mark as cacheable
}
],
messages=[
{
"role": "user",
"content": [
{
"type": "text",
"text": full_documentation, # large static reference doc
"cache_control": {"type": "ephemeral"} # second breakpoint
},
{"type": "text", "text": user_question} # variable part, no caching
]
}
]
)
print(response.usage.cache_creation_input_tokens) # tokens written to cache
print(response.usage.cache_read_input_tokens) # tokens read from cache
3. Placing cache breakpoints correctly
A cache breakpoint marks the end of a reusable block within the prompt. The Claude API allows multiple breakpoints within a single request, which can be used for staged prompt caching strategies: one breakpoint after the system prompt, another after a large reference document that changes less often than the conversation itself. Each breakpoint creates its own cache entry with its own validity.
The order in which blocks are placed determines the effectiveness of prompt caching: content that changes least frequently should come first, followed by content of medium change frequency, and finally the actually variable user request at the very end. If this order is violated, for example when a variable ID is embedded in the middle of an otherwise static system prompt, the cache breaks for the entire subsequent block, even if the rest is identical.
For multi turn conversations with a growing history, it is also worth adding a breakpoint at the end of the conversation so far, so that with every new user reply only the new contribution lies outside the cache while the entire prior dialogue is served from cache. This technique is especially effective in longer support chats or coding sessions with many back and forth messages.
{
"system": [
{
"type": "text",
"text": "<static system instructions, rarely changes>",
"cache_control": {"type": "ephemeral"}
}
],
"messages": [
{
"role": "user",
"content": [
{
"type": "text",
"text": "<large reference document, changes weekly>",
"cache_control": {"type": "ephemeral"}
},
{
"type": "text",
"text": "<conversation history so far>",
"cache_control": {"type": "ephemeral"}
},
{"type": "text", "text": "<newest user message, never cached>"}
]
}
]
}
4. TTL choice: 5 minutes or 1 hour
The Claude API offers two TTL options for prompt caching: a short five minute cache lifetime and a longer one hour variant at a somewhat higher write price. The right choice depends on the application's request pattern. For an interactive chat interface where users typically send several messages within a few minutes, the five minute TTL is usually sufficient and is the cheaper option.
For batch processing with longer pauses between requests, for example a daily analysis of a large document collection spread over several hours, the five minute TTL prevents the cache from being hit at all between requests. Here the one hour TTL pays off despite the higher write cost, because it significantly increases the hit rate over the entire processing period. A rough rule of thumb: once the average pause between requests noticeably exceeds five minutes, it is worth checking the one hour variant.
5. Typical use cases with high savings potential
The greatest lever for prompt caching arises where a large, stable context is repeatedly combined with different small requests. A support chatbot that sends the entire product documentation as context with every user request is a textbook example: the documentation rarely changes, the user question changes with every request. Without caching, the entire documentation is fully billed on every single request.
A second strong example is a coding assistant that needs the same large codebase as context for every request in order to suggest changes in the right context. Without prompt caching, the costs for repeatedly processing the same code add up to a substantial amount over an entire development session. Few shot prompting with many examples also benefits considerably: the example collection stays constant across many requests and is an excellent candidate for a cached block placed before the actual variable task.
import anthropic
client = anthropic.Anthropic()
def support_chatbot_reply(product_docs: str, user_question: str) -> str:
"""Product documentation stays constant across thousands of requests,
cache it once, pay full price only for the changing user question."""
response = client.messages.create(
model="claude-sonnet-4-5",
max_tokens=1024,
system=[
{
"type": "text",
"text": f"You are a support assistant. Reference documentation:\n\n{product_docs}",
"cache_control": {"type": "ephemeral"},
}
],
messages=[{"role": "user", "content": user_question}],
)
print(f"cache read: {response.usage.cache_read_input_tokens} tokens")
return response.content[0].text
6. Prompt caching in agentic workflows
Agentic systems, where Claude repeatedly calls tools in a loop and feeds intermediate results back into the same conversation history, benefit especially strongly from prompt caching. Each further round of the loop contains the entire history so far, including all previous tool calls and results, and without caching the cost per round grows linearly with the length of the history so far.
With a cache breakpoint at the end of the history so far before every new round, only the newly added portion, typically the latest tool result, is fully billed, while the entire historical context is served from cache. In agents with ten or more iteration steps, this difference turns the use of prompt caching from an optimization into an economic necessity.
import anthropic
client = anthropic.Anthropic()
def agent_loop(system_prompt: str, tools: list, conversation: list, max_turns: int = 10):
"""Run an agentic loop, caching the growing conversation history each turn."""
for turn in range(max_turns):
# Mark the last message of the history as a cache breakpoint:
# everything up to here is reused on the next iteration.
if conversation:
conversation[-1]["content"][-1]["cache_control"] = {"type": "ephemeral"}
response = client.messages.create(
model="claude-sonnet-4-5",
max_tokens=2048,
system=[{"type": "text", "text": system_prompt, "cache_control": {"type": "ephemeral"}}],
tools=tools,
messages=conversation,
)
print(f"Turn {turn}: cache read = {response.usage.cache_read_input_tokens} tokens")
if response.stop_reason != "tool_use":
return response
conversation.append({"role": "assistant", "content": response.content})
tool_result = execute_tools(response.content) # application specific
conversation.append({"role": "user", "content": [tool_result]})
return response
7. Measuring and monitoring cache hit rate
Without measurement, prompt caching remains a guess rather than a proven cost saving. Every Claude API response contains the fields cache_creation_input_tokens for newly written cache entries and cache_read_input_tokens for successful cache hits inside the usage object. Monitoring that logs these values per request and aggregates them over time makes it visible whether the chosen breakpoint placement is actually paying off.
A low hit rate despite configured breakpoints usually points to one of two problems: either the supposedly static prefix actually changes slightly on every request, for example due to an embedded timestamp, or the TTL is too short for the actual request pattern. A simple dashboard that plots the ratio of cache_read_input_tokens to total input tokens over time makes such regressions immediately visible before they show up as a surprise on the monthly bill.
cache_metrics = []
def record_usage(response) -> None:
"""Log cache metrics per request for later aggregation into a dashboard."""
usage = response.usage
total_input = usage.input_tokens + usage.cache_read_input_tokens
hit_rate = usage.cache_read_input_tokens / total_input if total_input else 0.0
cache_metrics.append({
"cache_read_tokens": usage.cache_read_input_tokens,
"cache_creation_tokens": usage.cache_creation_input_tokens,
"hit_rate": round(hit_rate, 3),
})
def average_hit_rate(window: int = 100) -> float:
"""Rolling average over the most recent requests, flags regressions early."""
recent = cache_metrics[-window:]
return sum(m["hit_rate"] for m in recent) / len(recent) if recent else 0.0
8. Pitfalls: when caching does not kick in
The most common pitfall in prompt caching is a hidden dynamic value inside a supposedly static block. A system prompt that contains the current time or a session ID invalidates the cache on every single request, because the text is never exactly identical. Such dynamic values strictly belong after the last cache breakpoint, never before it.
Another pitfall concerns the order of tool definitions: if tools are passed in a different order between two requests, even though the set of tools is identical, the prefix is considered different and the cache does not hit. Tool lists should therefore be built consistently in a fixed, deterministic order. Changing the model version between two requests also completely breaks cache continuity, since every cache entry is tied to a specific model.
9. Cost model comparison
The concrete cost impact of prompt caching depends on the ratio between cached and variable tokens. The following table compares typical cost factors against standard input tokens without naming specific prices, since these can change depending on model and provider.
| Token category | Relative cost factor | When relevant |
|---|---|---|
| Standard input tokens | Base factor 1.0x | Without caching, every request reprocessed in full |
| Cache write (5 min TTL) | Higher than base factor | First request of a new context |
| Cache write (1 hour TTL) | Slightly higher still | Batch processing with long pauses |
| Cache read (hit) | Well below base factor | Every follow up request with identical prefix |
The economic advantage of prompt caching comes from the number of cache hits relative to write operations. For a context that is written once and read a hundred times afterward, the savings are considerable. For a context used only once, the slightly higher write price exceeds the possible benefit, which is why prompt caching should be applied deliberately to reused portions, not blanket applied to every request.
Mironsoft
Claude API cost optimization and performance tuning
Claude API costs too high in your application?
We analyze existing prompt structures, place cache breakpoints correctly and set up monitoring for the cache hit rate so your Claude integration becomes noticeably cheaper and faster.
Cost audit
Analysis of existing prompt structures for caching potential
Cache strategy
Breakpoints and TTL choice matched to your application's request pattern
Monitoring
Dashboards for cache hit rate and ongoing cost control
10. Summary
Prompt caching strategies for cost savings pay off everywhere a large, stable context is repeatedly combined with small variable requests: support chatbots with static documentation, coding assistants with large codebases, and agentic workflows with a growing conversation history. Cache breakpoints must be placed so that content that changes less often consistently comes before content that changes more often.
The choice between a five minute and a one hour TTL depends on the application's actual request spacing, not on a blanket recommendation. Monitoring the fields cache_read_input_tokens and cache_creation_input_tokens makes the real effect visible and uncovers hidden dynamic values that unintentionally invalidate the cache. Anyone who applies prompt caching deliberately and with measurement lowers cost and latency at the same time, without any compromise on answer quality.
Prompt Caching Strategies for Cost Savings: Key Takeaways
Mind the order
Place static content before variable content. Cache breakpoints mark the end of reusable blocks.
Choose the right TTL
Five minutes for interactive chats, one hour for batch processing with longer pauses.
Measure the hit rate
Watch cache_read_input_tokens over time instead of just assuming cost savings.
Isolate dynamic values
Timestamps, session IDs and variable values always belong after the last cache breakpoint.