Magic Tools
AI TutorialsBy CooconMarch 29, 2026950 views11 min read

Claude Prompt Caching Guide: Reduce Repetition, Cost, and Latency

Prompt caching is one of the clearest ways to make repeated Claude requests cheaper and faster. Anthropic's official documentation describes it as a way to reuse static prompt prefixes such as system instructions, tool definitions, examples, and background context instead of sending the same material again on every request.

That matters most when your workload keeps repeating the same setup. If you are running the same agent, the same rubric, or the same reference material many times, prompt caching can remove a lot of wasted input tokens without changing the final answer.

This article originally only covered the theory. On 2026-09-10 I added a hands-on section at the end: real API calls, the same 28K-token system prefix sent 21 times, reading the three cache fields in usage, end-to-end latency, time to first token, and the bill converted at official prices. The short version: the cost win is an order of magnitude ($0.0719 → $0.0058 per request on a hit), the latency win at this scale is only about a hundred and fifty milliseconds.

What prompt caching is good for

Prompt caching works best when part of the prompt stays stable across many requests:

  • System instructions that rarely change
  • Tool definitions that stay the same
  • Long background context
  • Few-shot examples
  • Reusable reference documents

Anthropic's feature overview also places prompt caching alongside other production features such as batch processing, citations, and files support. That is a useful clue: this is primarily an API optimization feature, not a chat trick for casual users.

The basic idea

The workflow is simple:

  1. Put stable content at the beginning of the request.
  2. Mark the end of the reusable section with cache_control.
  3. Send later requests with the same prefix so Claude can reuse the cached content.

Anthropic recommends placing static content in a consistent order: tools, then system, then messages. The longest matching prefix is reused automatically, so you usually do not need to place cache breakpoints everywhere.

A practical setup pattern

Use prompt caching when your request has two parts:

  1. A reusable foundation, such as instructions, schema, examples, or source material.
  2. A changing task, such as a new user question or new document.

For example, a support triage agent might keep the same role instructions, escalation rubric, and response format in cache while swapping the incoming ticket body on each run. A document analysis workflow might cache the reference documents once and then ask different questions against them.

Important limits to know

Prompt caching is not a general shortcut for every request. Anthropic documents several practical limits:

  • The prompt must be long enough to qualify for caching.
  • Exact matches are required for cached prefixes.
  • Caches are isolated by organization.
  • Empty text blocks cannot be cached.
  • Thinking blocks cannot be cached directly.

There is also a time-to-live behavior. Anthropic supports a default short-lived cache and an extended one-hour option for some use cases. If you are designing a production workflow, you should verify which models and cache durations are currently supported before relying on them.

When caching helps most

Prompt caching is especially useful in workflows like:

  • Multi-step agents that reuse the same instructions
  • Internal tools with fixed rubrics
  • Long context analysis where source material rarely changes
  • Repeated batch jobs with the same setup

It is less useful when every request is completely different. If the system prompt, examples, and context all change every time, there is little to reuse.

Common mistakes

The most common mistakes are straightforward:

  • Caching content that changes too often
  • Assuming different prompt wording will still hit the same cache
  • Marking too little content as reusable
  • Treating prompt caching as a replacement for good prompt design

Caching only helps if the stable part of the request is actually stable. A messy prompt stays messy even when it is cheaper.

A simple rule

If you find yourself copy-pasting the same instructions, examples, or reference material into many Claude requests, that content is probably a caching candidate.

Hands-on: the same 63KB system prefix, sent 21 times

Background

I had been explaining the theory above for half a year without ever looking at what cache_read_input_tokens actually shows in a real response, or working out what "90% cheaper" means in cents for one request. More importantly, the docs list "cheaper" and "faster" side by side, and nobody had measured for me whether those two wins are the same size in my environment.

Analysis

Three things have to be measured separately to prove caching works:

  1. Evidence of a hit lives in exactly one place: input_tokens / cache_creation_input_tokens / cache_read_input_tokens in the response usage. The first request should show creation > 0 and read = 0; the second should be the reverse. Without those fields everything else is guesswork.
  2. Latency has to be decomposed. End-to-end time mixes network round trips, the proxy hop, queueing, and generation, and caching only touches the prefill part. So beyond end-to-end, I also stream and measure time to first token, with a tiny request without a long prefix as the baseline.
  3. Cost is converted at the official pricing page: Claude Sonnet 5 input $2 / MTok, 5-minute cache write $2.50 (1.25×), cache hit $0.20 (0.1×), output $10 (pricing, checked 2026-09-10).

Approach and choices

  • Model: claude-sonnet-5. I hit /v1/models first to see what the proxy actually serves. Opus 5 and Fable 5.1 were excluded: 2.5 to 5× the price for the same tokens, and this experiment needs no intelligence at all. Haiku 4.5 was excluded because its minimum cacheable prefix is 4096 tokens, the highest threshold of any current model, so its results would not generalize.
  • Material: the first 45 lines of this site's docs/CHANGELOG.md, 63,010 bytes, 35,262 characters, 28,207 tokens by count_tokens including the user message. A real long Chinese document. Random filler was excluded: the tokenizer shreds noise into tiny pieces, inflating the count and representing no real workload.
  • Cold/warm control: a one-line nonce at the top of the system block, changed every round. The first request in a round is guaranteed cold; the next two reuse the nonce and share the prefix. "Wait 5 minutes for expiry" was excluded: too slow and the TTL boundary is fuzzy.
  • Fixed output: thinking disabled, max_tokens: 16, and the user message is just "Reply with the single word OK." All 21 requests produced exactly 4 output tokens, so any latency difference can only come from the input side. "Ask the model to summarize the document" was excluded because output length would be random.
  • Node's built-in fetch against /v1/messages, no SDK, so the request body is fully visible: cache_control sits on the last block of the system array.
  • Auth goes through an Anthropic-compatible proxy (Authorization: Bearer + anthropic-version: 2023-06-01; this machine has no API key). That adds a hop to every latency number, which the TTFT run measures explicitly.

The request body (the nonce line changes per round):

{
  "model": "claude-sonnet-5",
  "max_tokens": 16,
  "thinking": { "type": "disabled" },
  "system": [
    {
      "type": "text",
      "text": "[bench 20260910T0211 prefix A1]\n\n<63KB of CHANGELOG text>",
      "cache_control": { "type": "ephemeral" }
    }
  ],
  "messages": [{ "role": "user", "content": "Reply with the single word OK." }]
}

The run

The script runs three groups with an 8-second gap between requests:

  • Group A: 5 rounds × 3 requests with cache_control. Each round is 1 cold request (fresh nonce) + 2 warm requests (same nonce).
  • Group B: 2 rounds × 2 requests, the same prefix twice, without cache_control, as the control.
  • Group C: pre-warm demo. First request with max_tokens: 0 (writes the cache, generates nothing), then a normal request that reads it.

Full output of all 21 requests: group A cold requests show cache_creation 28729 and warm requests cache_read 28729; the group B control always shows input 28757; the group C max_tokens 0 pre-warm is followed by a hit

The three raw usage objects side by side are the one picture this article most wants you to see:

Three real usage objects: cold request cache_creation_input_tokens 28729 / cache_read 0; warm request cache_read_input_tokens 28729 / input_tokens 28; the no-cache_control control shows input_tokens 28757 with both cache fields at 0

Results

100% hit rate. All 5 cold requests show cache_creation_input_tokens = 28729, all 10 warm requests show cache_read_input_tokens = 28729, and warm input_tokens drops to 28 (just the user message). The 4 control requests all show input_tokens = 28757 with both cache fields at 0. In other words the whole system prefix, plus whatever the proxy injects, went into the cache, and only the user message stayed outside it.

Per-request cost at official prices (the 4 output tokens are negligible):

Request type input cache_creation cache_read Cost per request End-to-end median
Cold (cache write) 28 28,729 0 $0.0719 4,306 ms
Warm (cache read, n=10) 28 0 28,729 $0.0058 3,695 ms
Control (no cache_control, n=4) 28,757 0 0 $0.0576 3,814 ms

The arithmetic:

  • A warm request is 91.9% cheaper than a cold one and 90% cheaper than the uncached control.
  • A cold request costs 25% more than uncached ($0.0719 vs $0.0576). That is the cache-write premium.
  • Same prefix sent twice: $0.0777 cached vs $0.1152 uncached, so it pays back on the second request. Ten times: $0.1241 vs $0.5760, 78% saved.
  • The whole experiment (including a smoke run and the TTFT group, 36 requests) cost about $1.3.

The latency win is much smaller than I expected. End-to-end median improved only 14% (4,306 → 3,695 ms), with a lot of jitter: in round 2 the warm request took 4,500 ms against 4,537 ms cold. So I added a streaming run measuring time to first token, with a tiny request (no system prompt) as the baseline:

Request TTFT median Range
Tiny (no system, baseline, n=2) 2,674 ms 2,668 – 2,680
Cold (cache write, n=3) 2,964 ms 2,847 – 3,169
Warm (cache read, n=3) 2,816 ms 2,657 – 3,036

Three streaming TTFT rounds: tiny request first token median 2674ms, cold 2964ms, warm 2816ms; caching cuts the extra latency from the long prefix from 290ms to 142ms

Two things fall out of that chart. First, the fixed overhead on my path is 2.7 seconds: even a bare "hi" takes 2.7 seconds to first token, which is the proxy hop plus cross-border network and has nothing to do with caching. Second, the 28K-token prefill on Sonnet 5 only adds about 290 ms, and a cache hit cuts that to about 142 ms. Half, yes, but 150 ms in absolute terms. At tens of thousands of tokens and behind a proxy, prompt caching is a cost feature, not a speed feature. The latency benefit should grow with longer prefixes and a more direct path, but I did not test that, so no claim.

max_tokens: 0 pre-warming works. The first group C request returned stop_reason: "max_tokens", output_tokens: 0, cache_creation_input_tokens: 28729, and the normal request right after it read cache_read 28729. Fire one of these before cold start and the user's first request already hits the cache.

Pitfalls

  1. The proxy returned 503 No available accounts, unrelated to caching. Right after the 7-request smoke run, every request failed with 503, even a bare "hi"; it happened again on the round-5 cold request and at the start of the TTFT group, and each time it recovered on its own after about 3 minutes. The root cause is not fully confirmed. The pattern (triggered by a burst of 28K-token cold requests, not by short prompts, recovering after a fixed few minutes) looks like the upstream account entering a rate-limit cooldown, during which the proxy has no account to route to. Fix: an 8-second gap between requests and a 60-second backoff with up to 4 retries on 503. A retried cold request must use a fresh nonce, otherwise, if the previous attempt reached upstream and wrote the cache, the retry is no longer cold.
  2. Do not blame the feature for the first 503. My first max_tokens: 0 pre-warm happened to land on a 503 and I nearly wrote "the proxy does not support max_tokens 0". The second run was fine. Check the environment before blaming the feature for the same error code.
  3. The proxy injects roughly 500 tokens into the prefix. A bare "hi" with no system prompt bills input_tokens: 516; count_tokens said my material was 28,207 but the bill said 28,757. The extra 550 is the injected content plus the nonce line. It sits inside the cached range (warm input_tokens is only 28), so it does not hurt the hit. Lesson: when cache_read does not match your own token count, suspect the middle layer before suspecting yourself.
  4. Cutting a file by bytes breaks UTF-8. head -c 40000 split a Chinese character in half and the script died with UnicodeDecodeError. Cut Chinese material by lines (head -n).
  5. Single-round latency numbers mean nothing. End-to-end jitter (2.6 to 4.5 s) is an order of magnitude larger than the caching benefit (about 150 ms), and in 5 rounds a warm request was slower than the cold one at least once. Take medians, and strip the fixed overhead with a tiny request, otherwise you cannot tell whether to believe "14% faster" or "51% faster".

The scripts live in the repo under tmp/2026-09-10-prompt-caching/ (bench.mjs for end-to-end and cost, ttft.mjs for streaming first token). They read credentials from the local Claude Code settings.json; swap in your own API key and they run as is.

Official References

Sources for the theory sections were reviewed on March 29, 2026; the benchmark and pricing check were done on September 10, 2026. Feature availability, model support, and pricing details can change, so confirm current behavior in the linked official Anthropic resources.

Related Articles

DeepSeek Harness Test: One Model, Three Harnesses — Claude Code 15/15, Codex CLI 15/15, Bare API 0/15 (and 5 Fake "Done"s)

DeepSeek Harness Test: One Model, Three Harnesses — Claude Code 15/15, Codex CLI 15/15, Bare API 0/15 (and 5 Fake "Done"s)

Same DeepSeek model (deepseek-v4-pro), three harnesses, five tasks (read / write / edit / run a command / multi-step), three rounds each, every side effect checked on disk. Claude Code on DeepSeek's Anthropic endpoint: 15/15, median 4.17s, ¥0.159 per task. Codex CLI 0.157.1 on the Responses endpoint: 15/15, median 15.52s, ¥0.022 per task — one seventh. Bare chat/completions: 0/15, and 5 of those rounds replied DONE or EDITED with nothing on disk. The differences are the harness: DeepSeek partitions its prompt cache by metadata.user_id, so every `claude -p` pays ~15K uncached tokens; Codex has no file tools and does everything through shell; on HTTP 500 Claude Code retries 10 times over ~175s while Codex quits in ~25s, and on 429 Codex doesn't retry; on 120KB of output Claude Code shows the first 2KB, Codex head + tail. And wire_api = "chat" is gone in Codex 0.157.1 — use responses.

claude-codeprompt-caching+6
hands-onSep 28, 202613 min
503

Claude's Aug 24 Outage: Elevated Errors Hit Opus 5, Fable 5, Mythos 5 for 2h46m

Full recap of the Aug 24 Claude API outage: elevated errors from 04:50–07:36 UTC across Claude Mythos 5, Fable 5, Opus 5 and Opus 4.8, hitting claude.ai, the API, Claude Code and Cowork. Includes the verbatim status-page timeline and tips for developers.

claudeapi+3
ai-tutorialsAug 25, 20263 min
553

OpenAI Didn't Cut the Price: GPT-5.6 Sol's 50% Off Expires September 18 and Excludes BYOK

GPT-5.6 Sol dropped from $5/$30 to $2.50/$15 on OpenRouter. The 50% is real, but three qualifiers went missing in transit: this is a platform-side promotion from OpenRouter and Vercel AI Gateway, with OpenAI's own pricing page still showing $5/$30; it expires September 18; and BYOK requests don't get it. SemiAnalysis raised a sharper question — these two platforms are a negligible share of OpenAI's volume but happen to be the main public data source for estimating model market share. Here's a same-source price table for 17 models, the 272K long-context pricing cliff, and a checklist for deciding whether to switch.

claudeopenai+6
ai-tutorialsAug 19, 20269 min
715

Claude Designed Proteins From Scratch — And the Prompt Is Public

Anthropic handed Claude a 30,000-token prompt, a GPU budget, and 15 protein targets, then walked away. It hit 14 of them at more than double the field's typical success rate, verified in two independent wet labs. The prompt and every data point are now on HuggingFace.

claudeanthropic+5
ai-tutorialsAug 19, 202612 min
839

Published by Magic Tools