Enable Prompt Caching

Su Suriya Ravichandran Updated 10 Nov 2026
7 min read ·Lesson 125 of 200

Two Ways to Turn It On

Lesson 121 marked one block with cache_control. The API offers two ways to place cache markers:

ApproachHowBest for
Automatic cachingOne cache_control field at the top level of the requestMulti-turn conversations, where the history grows and should be cached as it grows
Explicit breakpointscache_control on individual content blocksPrompts with several stable sections that change at different rates, or precise control over what is cached

Both use the same underlying cache and the same pricing. The difference is who decides where the cache boundary sits: with automatic caching, the API places it on the last cacheable block and moves it forward as the conversation grows.


Automatic Caching

Add cache_control at the top level of the request, next to model and messages:

response = client.messages.create(
    model="claude-opus-5-5",
    max_tokens=1024,
    cache_control={"type": "ephemeral"},            # top-level: automatic caching
    system="You are a helpful assistant that remembers our conversation.",
    messages=[
        {"role": "user", "content": "My name is Alex. I work on machine learning."},
        {"role": "assistant", "content": "Nice to meet you, Alex! How can I help today?"},
        {"role": "user", "content": "What did I say I work on?"},
    ],
)

The system caches everything up to and including the last cacheable block. In the next turn, the previous history is read from the cache, and only the new messages are processed. You do not need to move any markers as the conversation grows.

According to the documentation, automatic caching uses one of the four breakpoint slots, which matters when you combine it with explicit breakpoints (Lesson 129).


Explicit Breakpoints

Place cache_control on the blocks where caching should end. Anything before and including that block can be cached:

response = client.messages.create(
    model="claude-opus-5-5",
    max_tokens=1024,
    system=[
        {"type": "text", "text": "You are a legal document assistant."},
        {"type": "text", "text": LONG_AGREEMENT_TEXT,
         "cache_control": {"type": "ephemeral"}},   # cache up to and including this block
    ],
    messages=[{"role": "user", "content": "What is the termination notice period?"}],
)

The first system block is not marked, but it lies before the breakpoint, so it is part of the cached prefix. The breakpoint defines the boundary; the blocks before it are included automatically.

The prefix is built in a fixed order: tools, then system, then messages. A breakpoint caches everything before it in that order.


Choosing Between Them

SituationChoose
A chat where history grows with each turnAutomatic
A fixed system prompt plus a document, asked many questionsExplicit, on the last block of the stable content
Tools that rarely change, plus a system prompt that changes dailyExplicit, with two breakpoints (Lesson 129)
Automatic caching, plus a stable system prompt cached separatelyBoth, using two of the four slots

Automatic caching is the simplest starting point. Explicit breakpoints give precise control, and are needed whenever the cache boundary must sit somewhere other than the end of the request.


Reading the Result

Whichever approach you use, the response's usage fields show what happened:

FieldMeaning
cache_creation_input_tokensTokens written to the cache by this request
cache_read_input_tokensTokens read from the cache by this request
input_tokensTokens after the last breakpoint, which were not cached

The total input for the request is the sum of the three (Lesson 125).


Practical Example: Automatic Caching in a Conversation

This example runs a three-turn conversation with automatic caching, and prints the cache fields after each turn. The history grows, and the cached portion grows with it.

"""auto_cache.py: automatic caching across the turns of one conversation."""

from anthropic import Anthropic

client = Anthropic()
MODEL = "claude-opus-5-5"
SYSTEM = (
    "You are a friendly study assistant for an online Python course. "
    "Refer back to earlier messages when they are relevant, and keep answers short. "
    "Follow the course conventions: explain the concept, give one example, and name one pitfall. "
) * 12    # Repeated so the system prompt clears the minimum cacheable length

QUESTIONS = [
    "My name is Priya, and I'm learning Python for a data analysis job.",
    "What is a list comprehension?",
    "Remind me what my job is, and give one example that fits it.",
]


def run_conversation() -> None:
    history: list[dict] = []
    for question in QUESTIONS:
        history.append({"role": "user", "content": question})
        response = client.messages.create(
            model=MODEL,
            max_tokens=400,
            cache_control={"type": "ephemeral"},        # automatic caching
            system=SYSTEM,
            messages=history,
        )
        history.append({"role": "assistant", "content": response.content})
        usage = response.usage
        answer = "".join(b.text for b in response.content if b.type == "text").strip()
        print(f"Q: {question}")
        print(f"   written={usage.cache_creation_input_tokens} read={usage.cache_read_input_tokens} "
              f"uncached={usage.input_tokens}")
        print(f"A: {answer[:90]}\n")


if __name__ == "__main__":
    run_conversation()

Expected output (the answers and token counts vary):

Q: My name is Priya, and I'm learning Python for a data analysis job.
   written=<n1> read=0 uncached=<small>
A: Nice to meet you, Priya! ...

Q: What is a list comprehension?
   written=<n2> read=<n1-ish> uncached=<small>
A: ...

Q: Remind me what my job is, and give one example that fits it.
   written=<n3> read=<n1 + n2-ish> uncached=<small>
A: You're learning Python for data analysis. ...

How It Works

  1. cache_control={"type": "ephemeral"} at the top level turns on automatic caching. The request does not need any markers on individual blocks.
  2. The history is appended after each answer, so each request contains everything before it. The stored assistant turn is the full response.content, as Lesson 55 requires.
  3. Each request reads the earlier turns from the cache and writes the newest ones. The read value grows across turns, while uncached stays small.
  4. The system prompt is repeated 12 times only so the example clears the minimum cacheable length. In a real application, the system prompt would simply be long by design.
  5. The third answer uses the earlier name and job, which shows that caching does not change what Claude knows from the conversation. It changes only how that history is processed.

Common Mistakes

Forgetting the Minimum Length

What happens: a short conversation shows no cache activity, and the feature appears not to work.

Fix: remember that short prefixes are not cached, and check the usage fields.

Placing Automatic Caching and Explicit Breakpoints Carelessly

What happens: the combination uses up breakpoint slots, or puts the explicit boundary in an unexpected place.

Fix: count slots, and verify where each marker lands (Lesson 129).

Marking a Block That Changes Every Request

What happens: each request writes a new entry, and no reads happen. You pay the write premium every time.

Fix: place the marker on the last block that stays the same.

Mixing Up input_tokens

What happens: input_tokens looks small, and the cost seems lower than it is.

Fix: add all three input fields for the true total (Lesson 125).


Best Practices

  • Start with automatic caching for conversations.
  • Use explicit breakpoints for stable documents, system prompts, and tools.
  • Keep the cached prefix stable from request to request.
  • Check the usage fields on the first few requests of every new feature.
  • Use the same model across requests that should share a cache, because each model keeps its own entries.

Exercise

  1. Change MODEL to claude-sonnet-5-5, and compare the fields. Does the first request write to the cache?
  2. Remove the * 12 from SYSTEM. What changes in the output?
  3. Replace automatic caching with an explicit breakpoint on the system block. Do the usage numbers change?
  4. Explain why history.append({"role": "assistant", "content": response.content}) must store the full content rather than the text alone.
Show answers for steps 3 and 4

Step 3: the numbers should be similar, because both approaches cache the same prefix. The difference is that the explicit breakpoint covers only the system prompt. The conversation history after it is then not cached automatically, so the read value grows more slowly on turns 2 and 3. Automatic caching is the better choice when the conversation itself is the growing prefix.

Step 4: the stored history must match what the API produced, including any thinking blocks and other content. Keeping the full content preserves the exact prefix, which is what allows later requests to match the cache. Storing only the text would change the prefix, and a changed prefix cannot be read from the cache.

0 Comments

Reviewed before they appear

No comments yet.

Anthropic SDK Using Python
Anthropic SDK Intro Claude API Intro SDK Requirements Install Anthropic SDK Upgrade the SDK Create an API Key Set API Keys Use Environment Variables Import Anthropic Create a Client Send Your First Message Choose a Claude Model Set Max Tokens Read a Response Print Response Text Understand Message Blocks Use System Prompts Send User Messages Set Temperature Handle Stop Reasons Messages API Intro Create Messages Use Message Roles Send Conversation History Continue a Conversation Build a Chat Loop Reset Chat History Use Multiple Turns Inspect Message IDs Read Usage Data Write Clear Prompts Set a System Prompt Add Context to Prompts Use Prompt Templates Add Examples to Prompts Request JSON Output Use XML Tags Control Response Length Improve Prompt Quality Avoid Prompt Injection Read Text Blocks Read Content Blocks Check Stop Reasons Count Input Tokens Count Output Tokens Count Tokens Before Sending Limit Output Tokens Use Stop Sequences Read Request IDs Parse API Responses Streaming Intro Stream Text Output Use Stream Events Use Stream Helpers Get Final Messages Stream Async Responses Handle Stream Errors Build a Live Chat Stream Long Responses Close Streams Safely Build a Chatbot Keep Chat History Manage Chat Sessions Add Chat Memory Build a CLI Chatbot Build a Web Chatbot Use Flask with Claude Use FastAPI with Claude Return JSON from an API Add Chat Error Messages Async SDK Intro Create an Async Client Send Async Messages Use asyncio Run Parallel Requests Stream Async Text Handle Async Errors Set Async Timeouts Close Async Clients Choose Sync or Async Tool Use Intro Define a Tool Create Tool Schemas Send Tools to Claude Read Tool Calls Run Python Tools Return Tool Results Continue After Tool Use Control Tool Choice Handle Tool Errors Use the beta_tool Decorator Create a Tool Runner Add Tool Docstrings Validate Tool Inputs Use Multiple Tools Limit Tool Calls Log Tool Activity Build a Weather Tool Build a Search Tool Build a Calculator Tool Structured Output Intro Request JSON Data Validate JSON Output Use Pydantic Models Handle Invalid JSON Extract Fields from Text Generate Typed Data Use Image URLs Send Base64 Images Read PDFs with Claude Use Output Schemas Build Data Extraction Test Structured Responses Send Image Inputs Upload Files Use File IDs Process Text Files Summarize Documents Extract Table Data Handle File Errors Read Cache Usage Reduce Repeated Input Costs Debug Cache Misses Prompt Caching Intro Enable Prompt Caching Cache System Prompts Cache Long Context Test Cache Performance Use Cache Breakpoints Cache Best Practices Message Batches Intro Create a Message Batch Set Batch IDs Check Batch Status List Message Batches Get Batch Results Process Batch Outputs Handle Failed Batch Items Use Batches for Bulk Tasks Compare Batches and Requests Handle API Errors Handle Rate Limits Retry Failed Requests Set Request Timeouts Handle Network Errors Use Exponential Backoff Build Reliable API Calls Use Extended Thinking Log API Errors Track Request IDs Paginate API Results Set Thinking Budgets Read Thinking Blocks Use Tool Search Use Web Search Tools Use Computer Tools Use Citations Use Token Counting Read Raw Responses Set Custom Headers Use Claude on AWS Bedrock Use Claude on Vertex AI Use Claude on Microsoft Foundry Configure Cloud Credentials Choose a Cloud Provider Compare API Integrations Configure Provider Clients Handle Cloud Errors Use Cloud SDK Extras Deploy Cloud Apps Protect API Keys Use a .env File Ignore Secrets in Git Validate User Input Reduce Prompt Injection Limit Tool Permissions Avoid Unsafe Tool Calls Sanitize Tool Results Set Usage Limits Review Security Logs Test SDK Functions Mock API Responses Test Error Handling Test Streaming Code Measure Token Usage Track API Costs Configure Logging Deploy with Docker Deploy a FastAPI App Monitor Production Apps Build a Claude Chatbot Build a Text Summarizer Build a Code Explainer Build a JSON Extractor Build a PDF Assistant Build a Streaming Chat App Build a Tool-Calling Agent Build a Batch Processor Build a Research Assistant Build a Claude API Dashboard
Ask about this post
AI Ask about this post

Ask questions about Enable Prompt Caching and get answers drawn from it.

Signed-in readers only.