Prompt Caching for Cost Reduction with Claude Code: Complete Guide
As developers build increasingly sophisticated applications on top of large language models, two challenges consistently emerge: rising API costs and unacceptable latency. Anthropic's prompt caching feature, available through Claude Code and the broader Claude API, directly addresses both problems by allowing you to reuse large portions of prompts across multiple requests without paying full price each time. In this guide, we'll explore what prompt caching is, why it matters, how to implement it effectively, and the best practices that will keep your bills low and your responses fast.
What Is Prompt Caching?
Prompt caching is a feature that lets Claude store a prefix of your prompt on Anthropic's servers for a limited time. When you send a subsequent request that begins with the same prefix, Claude reuses the cached content instead of reprocessing it from scratch. This reduces both the input token cost and the time-to-first-token for that portion of the prompt.
The cache works on a prefix basis. This means the beginning of your prompt — up to the point where you mark a cache breakpoint — is stored. Any content after the breakpoint is processed normally on each request. You can define up to four cache breakpoints in a single request, allowing you to cache different sections of a complex prompt independently.
Cached content persists for five minutes by default, and each time you use the cache, that TTL refreshes. This makes it ideal for conversational applications, document Q&A systems, and agentic workflows where the same context is referenced repeatedly.
Why Prompt Caching Matters
The economics of prompt caching are compelling. When you read from the cache, you pay only 10% of the standard input token price. Writing to the cache costs 25% more than standard input tokens, but that surcharge is paid only once per cache write. The math favors caching whenever you expect to reuse the same prefix multiple times within the TTL window.
- Cost reduction: Cache reads cost 90% less than standard input tokens. For applications with large system prompts or document context, this can cut API bills dramatically.
- Lower latency: Cached prefixes skip the prefill computation step, reducing time-to-first-token significantly. Users perceive faster, more responsive applications.
- Larger effective context: Because cached content is cheaper to reprocess, you can afford to include richer context — longer system prompts, larger documents, more few-shot examples — without breaking the budget.
- Better agentic loops: Claude Code and similar agents iterate many times over the same context. Caching that context across iterations compounds savings quickly.
How Prompt Caching Works with Claude Code
Claude Code is Anthropic's command-line agentic coding tool. It leverages the Claude API under the hood, and prompt caching is applied automatically to reduce costs during extended coding sessions. However, if you're building your own integrations on top of the Claude API — or extending Claude Code's behavior — understanding how to control caching directly is essential.
The core mechanism is the cache_control parameter. You add it to any content block in your messages or system prompt to mark where the cache should end. Everything from the start of the prompt up to that breakpoint becomes the cached prefix.
Setting Up Your Environment
Before writing caching code, make sure you have the Anthropic Python SDK installed and your API key configured.
pip install anthropic
export ANTHROPIC_API_KEY="your-api-key-here"
Then initialize the client in your script:
import anthropic
client = anthropic.Anthropic()
Basic Prompt Caching Example
Let's start with a simple example. Suppose you have a large system prompt that defines your assistant's behavior, and you want to cache it across multiple user queries.
import anthropic
client = anthropic.Anthropic()
SYSTEM_PROMPT = """
You are an expert software engineer assistant. You help developers
write clean, maintainable, well-tested code. You always explain your
reasoning before providing code. You follow these principles:
1. Prefer composition over inheritance.
2. Write functions that do one thing well.
3. Include type hints in all Python code.
4. Add docstrings to every public function.
5. Suggest tests for any code you write.
... (imagine several thousand more tokens of detailed instructions)
"""
def ask_claude(question: str) -> str:
response = client.messages.create(
model="claude-sonnet-4-5-20250929",
max_tokens=1024,
system=[
{
"type": "text",
"text": SYSTEM_PROMPT,
"cache_control": {"type": "ephemeral"}
}
],
messages=[
{"role": "user", "content": question}
]
)
return response.content[0].text
# First call: cache is written (you pay a 25% write surcharge)
print(ask_claude("How do I structure a Python package?"))
# Second call within 5 minutes: cache is read (you pay only 10% of input cost)
print(ask_claude("What testing framework should I use?"))
Notice the cache_control key with {"type": "ephemeral"}. This tells Claude to cache everything up to that point. The first call writes the cache; subsequent calls within the TTL read from it.
Caching Large Documents
One of the most powerful use cases is caching large reference documents. Imagine building a documentation Q&A bot where users ask many questions about the same codebase or manual.
def ask_about_document(document_text: str, question: str) -> str:
response = client.messages.create(
model="claude-sonnet-4-5-20250929",
max_tokens=2048,
system=[
{
"type": "text",
"text": "You are a helpful documentation assistant. "
"Answer questions based only on the provided document."
},
{
"type": "text",
"text": f"<document>\n{document_text}\n</document>",
"cache_control": {"type": "ephemeral"}
}
],
messages=[
{"role": "user", "content": question}
]
)
return response.content[0].text
# Load a large document once
with open("api_reference.md", "r") as f:
doc = f.read()
# Many questions reuse the cached document
questions = [
"How do I authenticate requests?",
"What is the rate limit for the free tier?",
"How do I paginate results?",
"What error codes can the API return?",
]
for q in questions:
answer = ask_about_document(doc, q)
print(f"Q: {q}\nA: {answer}\n")
In this pattern, the document is cached on the first call. Each subsequent question pays only 10% of the input cost for that large document block, while the small system instruction and user question are processed at standard rates.
Multi-Turn Conversations with Caching
For chat applications, you want to cache the growing conversation history so that each new turn doesn't reprocess everything from scratch. Place the cache breakpoint at the end of the conversation history, right before the new user message.
conversation_history = [
{"role": "user", "content": "What is dependency injection?"},
{"role": "assistant", "content": "Dependency injection is a design pattern..."},
{"role": "user", "content": "Can you show me a Python example?"},
{"role": "assistant", "content": "Certainly! Here's a simple example..."},
]
new_question = "How does this compare to the service locator pattern?"
# Build messages with cache breakpoint at the end of history
messages = []
for msg in conversation_history:
messages.append(msg)
# Add the new user message with a cache_control on the last history item
messages[-1]["content"] = [
{
"type": "text",
"text": messages[-1]["content"],
"cache_control": {"type": "ephemeral"}
}
]
messages.append({"role": "user", "content": new_question})
response = client.messages.create(
model="claude-sonnet-4-5-20250929",
max_tokens=1024,
system="You are a helpful programming tutor.",
messages=messages
)
print(response.content[0].text)
Each turn, the entire prior conversation is cached. As the conversation grows, the savings compound because you only pay full price for the newest message.
Using Multiple Cache Breakpoints
The API supports up to four cache breakpoints per request. This is useful when your prompt has distinct sections that change at different rates — for example, a static system prompt, a semi-static document, and a growing conversation history.
response = client.messages.create(
model="claude-sonnet-4-5-20250929",
max_tokens=1024,
system=[
{
"type": "text",
"text": STATIC_SYSTEM_PROMPT,
"cache_control": {"type": "ephemeral"}
},
{
"type": "text",
"text": LARGE_REFERENCE_DOC,
"cache_control": {"type": "ephemeral"}
}
],
messages=[
{"role": "user", "content": "Summarize the key points."},
{"role": "assistant", "content": "Here are the key points..."},
{
"role": "user",
"content": [
{
"type": "text",
"text": "Now explain section 3 in detail.",
"cache_control": {"type": "ephemeral"}
}
]
}
]
)
Here we use three breakpoints: one for the system prompt, one for the reference document, and one for the conversation prefix. If the document changes but the system prompt stays the same, only the document cache is invalidated — the system prompt cache remains valid.
Monitoring Cache Usage
The API response includes token usage details that tell you exactly how caching performed. Always inspect these fields to verify your caching strategy is working.
response = client.messages.create(
model="claude-sonnet-4-5-20250929",
max_tokens=1024,
system=[
{
"type": "text",
"text": SYSTEM_PROMPT,
"cache_control": {"type": "ephemeral"}
}
],
messages=[{"role": "user", "content": "Hello!"}]
)
usage = response.usage
print(f"Input tokens: {usage.input_tokens}")
print(f"Output tokens: {usage.output_tokens}")
print(f"Cache creation tokens: {usage.cache_creation_input_tokens}")
print(f"Cache read tokens: {usage.cache_read_input_tokens}")
On the first call, you'll see cache_creation_input_tokens populated with the cached prefix size. On subsequent calls within the TTL, you'll see cache_read_input_tokens populated instead. If both are zero, your cache isn't being used — check that your prefix is truly identical between calls.
Best Practices for Prompt Caching
To get the most out of prompt caching, follow these guidelines:
- Cache large blocks: The minimum cacheable prefix is 1,024 tokens for Claude Sonnet and Opus models, and 2,048 tokens for Haiku. Caching tiny prompts provides negligible savings and may actually cost more due to the write surcharge.
- Keep cached prefixes identical: Even a single character difference invalidates the cache. Avoid injecting timestamps, random IDs, or dynamic content into cached sections. Place variable content after the cache breakpoint.
- Structure prompts from static to dynamic: Put the most stable content first (system instructions, reference docs) and the most variable content last (user messages, timestamps). This maximizes cache hit rates.
- Warm the cache proactively: If you know users will interact with a document, send a lightweight initial request to populate the cache before the first real query arrives. This shifts the write surcharge to a setup step.
- Monitor TTL carefully: The five-minute TTL refreshes on each cache hit. If your traffic is bursty with gaps longer than five minutes, consider sending periodic keep-alive requests to prevent cache expiration during active sessions.
- Use breakpoints strategically: Don't waste all four breakpoints on small sections. Reserve them for genuinely large, independently varying blocks. Each breakpoint adds overhead, so fewer is often better.
- Measure before and after: Track your token usage and costs before enabling caching, then compare. The
cache_read_input_tokensmetric is your direct evidence of savings. - Be careful with tool definitions: In agentic workflows, tool schemas are part of the cached prefix. If you dynamically modify tool definitions between calls, you'll invalidate the cache. Keep tool definitions stable.
Common Pitfalls to Avoid
Even experienced developers run into caching issues. Here are the most frequent mistakes:
- Placing cache_control on the wrong block: The breakpoint must be on the last block you want cached. If you place it on the first of several system blocks, only that first block is cached.
- Forgetting that caching is prefix-based: You cannot cache a section in the middle of a prompt while leaving the beginning uncached. The cache always starts from the beginning of the prompt.
- Exceeding the breakpoint limit: Using more than four breakpoints results in an API error. Plan your cache structure to stay within the limit.
- Ignoring cache write costs: If your use case involves single requests with no reuse, caching actually increases costs by 25%. Only enable it when you expect multiple hits within the TTL.
Conclusion
Prompt caching is one of the highest-leverage optimizations available to developers building on Claude. By structuring your prompts to separate stable, reusable content from dynamic per-request content, you can reduce input token costs by up to 90% and dramatically improve response latency. Whether you're building a document Q&A system, a multi-turn chatbot, or an agentic coding workflow with Claude Code, the principles are the same: cache the largest stable prefix you can, monitor your cache hit metrics, and let the TTL work in your favor. Start by instrumenting your existing API calls to measure current costs, then introduce cache breakpoints incrementally and observe the savings. With thoughtful implementation, prompt caching transforms expensive, slow LLM applications into efficient, responsive ones — without sacrificing capability or context depth.