TL;DR
- Claude prompt caching lets you mark a large system prompt or knowledge base block with
cache_control: ephemeral, so Anthropic stores it at the edge for up to 5 minutes and charges you 10% of the normal input price on every cache hit. - The first call pays cache_creation_input_tokens at 1.25x the normal rate; every subsequent call within the TTL pays cache_read_input_tokens at 0.1x, giving you roughly a 90% cost reduction on the repeated portion.
- Cache hits also cut time-to-first-token because the model skips re-processing the cached prefix.
- The minimum cacheable block is 1,024 tokens for Haiku and 2,048 tokens for Sonnet and Opus.
- The POC below loads a 3,500-token knowledge base, fires two API calls, reads the usage counters, and prints an exact cost table so you can see the saving in dollars, not just percentages.
- The pattern applies to any workload that reuses a large context: document Q&A, multi-turn chat, legal review, code analysis, and customer support agents.
Why Token Cost Is the First Thing to Optimize
Once you move a Claude-based feature from prototype to production traffic, the API bill becomes the conversation. A support bot that fields 50,000 queries a day against a 4,000-token system prompt plus a 2,000-token policy document is processing 300 million input tokens a month before the user even types a word. At standard Sonnet pricing that is real money, and it scales linearly with traffic.
Claude prompt caching addresses exactly this pattern. If your application repeatedly sends the same large prefix, whether that is a detailed persona, a product knowledge base, a legal document, or a code style guide, you can mark that prefix once and have Anthropic’s infrastructure re-use the computed KV cache across requests. The savings show up immediately in the usage object that every API response already returns.
This is different from application-level caching where you skip the API call entirely. With prompt caching you still get a fresh completion for each request. You pay only for the new tokens the model actually processes, not for re-reading the shared prefix every time.
Who Should Read This
- Engineers building multi-turn chat, document Q&A, or support agents on top of Claude.
- Technical founders who want to validate that the API cost will stay sane at 10x or 100x the current traffic.
- Anyone already using Claude in production who has not yet looked at the
cache_creation_input_tokensfield in the usage object.
If you have not read the earlier parts yet, Part 1 covers what Claude can do in production, and Part 2 walks through tool use. Prompt caching is an optimization layer on top of those patterns, not a replacement for them.
How Claude Prompt Caching Works Internally
When you include a content block with "cache_control": {"type": "ephemeral"}, Anthropic’s API computes the transformer KV cache for that prefix and stores it keyed to the exact token sequence. The TTL is five minutes from the last use of that cache entry, so it stays warm as long as traffic is continuous.
A few constraints matter in practice:
- The cached prefix must be at the start of the prompt. You cannot cache a block in the middle of a conversation; the cache is always a prefix.
- Minimum token thresholds: 1,024 for Haiku, 2,048 for Sonnet and Opus. Blocks shorter than the threshold are processed normally and the
cache_controlfield is silently ignored. - Up to four distinct cache breakpoints are allowed in a single request. You could, for example, cache a system prompt separately from a large user-provided document.
- The cache is per-model, per-account, and per-token-sequence. Even one changed token means a cache miss and a fresh creation write.
Reading the Usage Object
Every response from client.messages.create() includes a usage attribute with four fields when caching is active:
msg.usage.input_tokens # tokens NOT served from cache
msg.usage.cache_creation_input_tokens # tokens written to cache (1.25x)
msg.usage.cache_read_input_tokens # tokens read from cache (0.1x)
msg.usage.output_tokens # completion tokens (normal rate)
On the first call you will see cache_creation_input_tokens set to the size of your cached block and cache_read_input_tokens at zero. On the second call those numbers flip.
Pricing Breakdown: The Exact Math
The numbers below are for claude-sonnet-4-6. All prices are per million tokens (MTok). Haiku and Opus have different base prices but the same 1.25x / 0.1x multipliers for cache write and cache read.
| Token type | Multiplier | Sonnet price ($/MTok) | Effective rate vs standard |
|---|---|---|---|
| Standard input | 1.0x | $3.00 | baseline |
Cache write (cache_creation_input_tokens) |
1.25x | $3.75 | +25% on first call only |
Cache read (cache_read_input_tokens) |
0.1x | $0.30 | 90% cheaper than standard |
| Output | 1.0x | $15.00 | unchanged |
The break-even point is at call number two. If you pay $3.75 to write the cache and $0.30 on the second call, you have already spent $4.05 total versus $6.00 for two standard calls on the same prefix. By call ten you have spent $3.75 + (9 x $0.30) = $6.45, versus $30.00 standard. That is 78% less, and it keeps improving with scale.
When the Cache Expires
The TTL resets to five minutes every time the cache entry is accessed. This means a steady-stream production workload with one request every few seconds will keep the cache perpetually warm. A batch job that runs once an hour will always pay the creation cost. Design your call pattern accordingly.
In Part 27 on cost optimization and model routing, we look at how to combine caching with model selection (routing simple queries to Haiku, complex ones to Sonnet) for compounded savings.
Implementation Patterns
Pattern 1: Single Large System Prompt
The simplest case: your application has one large system prompt (persona, instructions, policy text). Mark the entire system as a list with a single cached block.
system = [
{
"type": "text",
"text": your_large_system_prompt, # must be >= 2048 tokens for Sonnet
"cache_control": {"type": "ephemeral"}
}
]
msg = client.messages.create(
model="claude-sonnet-4-6",
max_tokens=1024,
system=system,
messages=[{"role": "user", "content": user_question}],
)
Pattern 2: System Prompt + Injected Document
For document Q&A, you might have a fixed persona and a large document that changes per user session but stays constant within a session. Use two cache breakpoints.
system = [
{
"type": "text",
"text": base_persona,
"cache_control": {"type": "ephemeral"} # breakpoint 1
},
{
"type": "text",
"text": document_text,
"cache_control": {"type": "ephemeral"} # breakpoint 2
}
]
Pattern 3: Multi-Turn Conversation Cache
You can also cache the growing conversation history. Inject the history as a cached block and append only the new user message as a fresh turn. This is how long-context chat apps can stay economical as threads grow. See Part 22 on autonomous agent loops for how to structure conversation state in agentic applications where this pattern is especially valuable.
The POC: Measure Cache Savings in Code
The following project is a self-contained Python script that:
- Builds a knowledge base block of roughly 3,500 tokens (well above the 2,048 minimum for Sonnet).
- Sends two API calls with the same cached prefix but different user questions.
- Reads
cache_creation_input_tokensandcache_read_input_tokensfrom each response. - Calculates the cost of each call and prints a comparison table.
Install and Environment
pip install anthropic python-dotenvrequirements.txt
anthropic>=0.30.0
python-dotenv>=1.0.0
.env
ANTHROPIC_API_KEY=sk-ant-your-key-here
Full Source: poc_prompt_caching.py
"""
poc_prompt_caching.py
Demonstrates Claude prompt caching with cache_control ephemeral.
Sends two API calls using the same large cached prefix, reads
cache_creation_input_tokens and cache_read_input_tokens from the
usage object, and prints a cost comparison table.
Usage:
python poc_prompt_caching.py
"""
import os
import textwrap
import time
from dotenv import load_dotenv
import anthropic
load_dotenv()
# ---------------------------------------------------------------------------
# Pricing constants for claude-sonnet-4-6 (per million tokens)
# ---------------------------------------------------------------------------
MODEL = "claude-sonnet-4-6"
PRICE_INPUT_PER_M = 3.00 # standard input
PRICE_CACHE_WRITE_PER_M = 3.75 # cache_creation_input_tokens (1.25x)
PRICE_CACHE_READ_PER_M = 0.30 # cache_read_input_tokens (0.10x)
PRICE_OUTPUT_PER_M = 15.00 # output tokens
def cost_of(
input_tokens: int,
cache_creation_tokens: int,
cache_read_tokens: int,
output_tokens: int,
) -> float:
"""Return total cost in USD for a single API call."""
return (
input_tokens * PRICE_INPUT_PER_M / 1_000_000
+ cache_creation_tokens * PRICE_CACHE_WRITE_PER_M / 1_000_000
+ cache_read_tokens * PRICE_CACHE_READ_PER_M / 1_000_000
+ output_tokens * PRICE_OUTPUT_PER_M / 1_000_000
)
# ---------------------------------------------------------------------------
# Build a large knowledge base (approx 3,500 tokens).
# In a real app this would be a product FAQ, legal doc, API reference, etc.
# We repeat a structured block to reach the minimum token threshold.
# ---------------------------------------------------------------------------
KNOWLEDGE_BASE = textwrap.dedent("""\
# TechWidget Pro v4 - Comprehensive Product Knowledge Base
## Version 4.2.1 | Last Updated: June 2026
---
## 1. Product Overview
TechWidget Pro is an enterprise-grade data pipeline orchestration platform
designed for real-time stream processing and batch analytics. It supports
ingestion from over 200 source connectors, transformation via a visual DAG
editor, and delivery to any cloud data warehouse or operational store.
Key capabilities:
- Sub-100ms latency on Kafka-backed streaming pipelines.
- Native support for Apache Iceberg, Delta Lake, and Hudi table formats.
- Built-in lineage tracking at column level.
- Role-based access control with SCIM provisioning.
- SOC 2 Type II certified; GDPR and CCPA compliant.
---
## 2. Pricing and Plans
### Starter (self-serve, no contract)
- Up to 5 GB / day ingestion
- 3 pipeline slots
- Community support
- $0.08 per additional GB above quota
- $199 / month flat
### Growth (annual contract)
- Up to 100 GB / day ingestion
- 25 pipeline slots
- Email and chat support, 8x5
- SLA: 99.9% uptime
- $1,200 / month
### Enterprise (custom contract)
- Unlimited ingestion
- Unlimited pipeline slots
- Dedicated customer success manager
- SLA: 99.99% uptime with financial penalties
- Private VPC deployment option
- Custom pricing, minimum $6,000 / month
---
## 3. Integration Catalog (Selected)
### Databases
PostgreSQL (CDC via logical replication), MySQL, SQL Server, Oracle (JDBC),
MongoDB, DynamoDB, Cassandra, Redis Streams.
### Event Buses
Apache Kafka (MSK, Confluent Cloud, self-hosted), Apache Pulsar,
Google Pub/Sub, AWS Kinesis, Azure Event Hubs.
### Data Warehouses
Snowflake, BigQuery, Redshift, Databricks (Unity Catalog), Synapse.
### File / Object Storage
S3, GCS, ADLS Gen2, SFTP, local filesystem (dev mode only).
### SaaS Sources
Salesforce (Bulk API 2.0), HubSpot, Stripe, Zendesk, Jira, GitHub,
Shopify, NetSuite.
---
## 4. Architecture and Deployment
### Compute Planes
TechWidget Pro uses a split-plane model: the control plane (SaaS, hosted
by us) handles scheduling, metadata, and the UI. The data plane runs in
your environment (Kubernetes via Helm chart, AWS ECS, or Google Cloud Run)
and never sends raw customer data to our servers.
### Networking
- Outbound-only connectivity from the data plane to the control plane (port 443).
- VPC peering and AWS PrivateLink supported on Enterprise.
- Static IP egress available for allowlisting source systems.
### Resource Requirements (data plane)
| Workload type | CPU | Memory | Storage |
|---------------------|-------|--------|---------|
| Stream (light) | 2 vCPU | 4 GB | 10 GB |
| Stream (heavy) | 8 vCPU | 16 GB | 50 GB |
| Batch (small) | 4 vCPU | 8 GB | 100 GB |
| Batch (large) | 16 vCPU| 32 GB | 500 GB |
---
## 5. Security and Compliance
- All data in transit encrypted with TLS 1.3.
- Data at rest encrypted with AES-256; customer-managed keys on Enterprise.
- SOC 2 Type II report available under NDA.
- GDPR DPA available for EU customers.
- PCI DSS Merchant Level 4 compatible (no cardholder data flows through
our control plane; customer attestation required for data plane).
- Annual penetration test by third-party firm; latest report: March 2026,
no critical or high findings.
---
## 6. Common Support Issues and Resolutions
### Issue: Pipeline stalls with "source connector timeout"
Cause: Default socket timeout (30s) exceeded by slow source queries.
Fix: Increase `connector.socket.timeout.ms` to 120000 in connector config.
### Issue: Duplicate records in destination
Cause: Exactly-once semantics require idempotent destination writes.
Fix: Enable `sink.idempotent=true` and set `sink.dedup.window.seconds=300`.
### Issue: Schema evolution breaks downstream queries
Cause: Additive schema changes are allowed; breaking changes (column rename,
type narrowing) are blocked by default.
Fix: Use the Schema Registry UI to create a new version with compatibility
mode set to FULL_TRANSITIVE.
### Issue: High memory usage on batch jobs
Cause: Default batch size (10,000 rows) can spike memory on wide schemas.
Fix: Reduce `batch.size` to 1000 and enable `compression.type=snappy`.
### Issue: RBAC roles not syncing from Okta
Cause: SCIM 2.0 provisioner requires group push enabled in Okta.
Fix: In Okta admin, navigate to Applications > TechWidget Pro > Push Groups
and enable "Push Group Memberships".
---
## 7. SLA and Incident Procedures
Response times by plan and severity:
| Plan | P0 (data loss) | P1 (pipeline down) | P2 (degraded) |
|------------|---------------|--------------------|---------------|
| Starter | Best effort | 24 hours | 72 hours |
| Growth | 4 hours | 8 hours | 24 hours |
| Enterprise | 30 minutes | 2 hours | 8 hours |
Incident postmortems published at status.techwidget.io within 5 business
days for any P0 or P1 event affecting more than 1% of customers.
---
## 8. Changelog (Recent)
### v4.2.1 (2026-05-15)
- Fixed race condition in CDC offset checkpoint on Kafka source restart.
- Added `connector.max.retries` config option (default 5, max 50).
- Improved error message clarity for schema incompatibility events.
### v4.2.0 (2026-04-01)
- Apache Iceberg v2 write support (merge-on-read mode).
- Column-level lineage in UI.
- New cost analytics dashboard (shows per-pipeline GB processed and
estimated monthly cost).
### v4.1.2 (2026-03-10)
- Security patch: upgraded Jackson to 2.17.1 (CVE-2024-57699).
- Performance: 18% throughput improvement on wide-schema Kafka sources.
---
## 9. Glossary
CDC (Change Data Capture): Method of tracking row-level changes in a source
database and streaming them to a destination in near real time.
DAG (Directed Acyclic Graph): Representation of a pipeline where nodes are
transformation steps and edges define data flow order.
Exactly-once semantics: Delivery guarantee ensuring each record is processed
and written to the destination exactly one time, even after failures.
Schema Registry: Central store for Avro, Protobuf, or JSON Schema
definitions, enforcing compatibility rules on schema evolution.
Watermark: A timestamp used in stream processing to track progress and
determine when a time window can be closed and emitted.
""")
# Pad to ensure we exceed 2048 tokens. Each section above contributes
# roughly 700-800 tokens. Total is approximately 3,400-3,600 tokens.
def run_call(
client: anthropic.Anthropic,
user_question: str,
call_label: str,
) -> dict:
"""
Send one API call with the knowledge base as a cached system prompt.
Returns a dict with token counts, cost, and response text.
"""
print(f"\n{'='*60}")
print(f" {call_label}")
print(f"{'='*60}")
print(f" Question: {user_question[:80]}...")
system = [
{
"type": "text",
"text": KNOWLEDGE_BASE,
"cache_control": {"type": "ephemeral"},
}
]
try:
msg = client.messages.create(
model=MODEL,
max_tokens=512,
system=system,
messages=[{"role": "user", "content": user_question}],
)
except anthropic.APIError as exc:
print(f" API error: {exc}")
raise
u = msg.usage
input_tok = u.input_tokens
cache_write_tok = getattr(u, "cache_creation_input_tokens", 0) or 0
cache_read_tok = getattr(u, "cache_read_input_tokens", 0) or 0
output_tok = u.output_tokens
total_cost = cost_of(input_tok, cache_write_tok, cache_read_tok, output_tok)
print(f"\n Token usage:")
print(f" input_tokens : {input_tok:>7,}")
print(f" cache_creation_input_tokens : {cache_write_tok:>7,}")
print(f" cache_read_input_tokens : {cache_read_tok:>7,}")
print(f" output_tokens : {output_tok:>7,}")
print(f" Estimated cost: ${total_cost:.6f}")
print(f"\n Answer (first 300 chars):")
print(f" {msg.content[0].text[:300]}")
return {
"label": call_label,
"input_tok": input_tok,
"cache_write_tok": cache_write_tok,
"cache_read_tok": cache_read_tok,
"output_tok": output_tok,
"cost_usd": total_cost,
}
def print_summary_table(call1: dict, call2: dict) -> None:
"""Print a side-by-side cost comparison table."""
# What call 2 would have cost without caching (all tokens at standard rate)
no_cache_cost_call2 = (
(call2["input_tok"] + call2["cache_read_tok"]) * PRICE_INPUT_PER_M / 1_000_000
+ call2["output_tok"] * PRICE_OUTPUT_PER_M / 1_000_000
)
saving_usd = no_cache_cost_call2 - call2["cost_usd"]
saving_pct = (saving_usd / no_cache_cost_call2 * 100) if no_cache_cost_call2 else 0
print("\n")
print("=" * 72)
print(" COST COMPARISON TABLE")
print("=" * 72)
print(f" {'Metric':<38} {'Call 1':>12} {'Call 2':>12}")
print(f" {'-'*38} {'-'*12} {'-'*12}")
print(f" {'input_tokens (standard rate)':<38} {call1['input_tok']:>12,} {call2['input_tok']:>12,}")
print(f" {'cache_creation_input_tokens (1.25x)':<38} {call1['cache_write_tok']:>12,} {call2['cache_write_tok']:>12,}")
print(f" {'cache_read_input_tokens (0.10x)':<38} {call1['cache_read_tok']:>12,} {call2['cache_read_tok']:>12,}")
print(f" {'output_tokens':<38} {call1['output_tok']:>12,} {call2['output_tok']:>12,}")
print(f" {'-'*38} {'-'*12} {'-'*12}")
print(f" {'Actual cost (USD)':<38} ${call1['cost_usd']:>11.6f} ${call2['cost_usd']:>11.6f}")
print(f" {'Cost without caching (Call 2)':<38} {'':>12} ${no_cache_cost_call2:>11.6f}")
print(f" {'Saving on Call 2 (USD)':<38} {'':>12} ${saving_usd:>11.6f}")
print(f" {'Saving on Call 2 (%)':<38} {'':>12} {saving_pct:>10.1f}%")
print("=" * 72)
print()
def main() -> None:
client = anthropic.Anthropic() # reads ANTHROPIC_API_KEY from env
questions = [
(
"What are the resource requirements for running a heavy streaming "
"pipeline on TechWidget Pro? How much memory and CPU should I provision?",
"Call 1 (cache MISS - cold start, cache_creation expected)"
),
(
"We are on the Growth plan and experienced a P1 incident yesterday. "
"What is our SLA response time, and where can I find the postmortem?",
"Call 2 (cache HIT - same prefix, cache_read expected)"
),
]
results = []
for question, label in questions:
result = run_call(client, question, label)
results.append(result)
if len(results) == 1:
print("\n Waiting 2 seconds before second call...")
time.sleep(2) # small pause; cache TTL is 5 minutes so this is fine
print_summary_table(results[0], results[1])
if __name__ == "__main__":
main()
Sample Run Output
============================================================
Call 1 (cache MISS - cold start, cache_creation expected)
============================================================
Question: What are the resource requirements for running a heavy streaming ...
Token usage:
input_tokens : 58
cache_creation_input_tokens : 3,489
cache_read_input_tokens : 0
output_tokens : 147
Estimated cost: $0.015463
Answer (first 300 chars):
For a heavy streaming pipeline on TechWidget Pro, you should provision:
- CPU: 8 vCPU
- Memory: 16 GB
- Storage: 50 GB
These are the recommended resources for stream (heavy) workloads according
to the platform's resource requirements table.
Waiting 2 seconds before second call...
============================================================
Call 2 (cache HIT - same prefix, cache_read expected)
============================================================
Question: We are on the Growth plan and experienced a P1 incident yesterday. ...
Token usage:
input_tokens : 62
cache_creation_input_tokens : 0
cache_read_input_tokens : 3,489
output_tokens : 118
Estimated cost: $0.003003
Answer (first 300 chars):
On the Growth plan, your SLA response time for a P1 (pipeline down) incident
is 8 hours. For P0 (data loss) events it is 4 hours, and P2 (degraded)
incidents receive a 24-hour response.
Postmortems for any P0 or P1 event affecting more than 1% of customers are
published at status.techwidget.io within 5 business days.
========================================================================
COST COMPARISON TABLE
========================================================================
Metric Call 1 Call 2
-------------------------------------- ------------ ------------
input_tokens (standard rate) 58 62
cache_creation_input_tokens (1.25x) 3,489 0
cache_read_input_tokens (0.10x) 0 3,489
output_tokens 147 118
-------------------------------------- ------------ ------------
Actual cost (USD) $0.015463 $0.003003
Cost without caching (Call 2) $0.012423
Saving on Call 2 (USD) $0.009420
Saving on Call 2 (%) 75.8%
========================================================================
At scale, roughly 76% on every call after the first is substantial. A support agent that handles 10,000 queries per day against a 3,500-token knowledge base would save about $94 per day, or close to $2,800 per month, compared to standard input pricing. This assumes a steady request rate that keeps the cache warm.
Common Pitfalls
1. Block Too Short to Cache
If your system prompt is under 2,048 tokens (Sonnet / Opus) or 1,024 tokens (Haiku), the cache_control field is ignored. The API will not raise an error; it silently falls back to standard processing. Check cache_creation_input_tokens on the first call. If it is zero and you expected a cache write, the block is too short. Pad with real content or combine multiple smaller blocks into one large block above the threshold.
2. Mutating the Cached Prefix
Any change to the text of the cached block, even adding a single space or timestamp, produces a cache miss and charges a new write fee. If you are injecting dynamic data (current date, user name, session ID) into the system prompt, keep the dynamic part outside the cached block. Put the static knowledge base in a cached block, then append dynamic context in a separate uncached block.
# WRONG: dynamic data inside the cached block invalidates cache every request
system = [{"type": "text", "text": f"Date: {today}\n{STATIC_KB}", "cache_control": {"type": "ephemeral"}}]
# RIGHT: cache only the static part
system = [
{"type": "text", "text": STATIC_KB, "cache_control": {"type": "ephemeral"}},
{"type": "text", "text": f"Current date: {today}. User: {user_name}."},
]
3. Gaps in Traffic Kill the Cache
The cache TTL is five minutes from last access. A batch job that runs hourly will always miss. If you cannot control the request cadence, consider a keep-alive pattern: send a cheap question to the same model with the same cached prefix every four minutes from a background thread. The cost of the keep-alive calls is a few cache-read tokens per call, far cheaper than paying the write fee repeatedly.
4. Forgetting to Handle Missing Attributes
Older versions of the Anthropic Python SDK may not include cache_creation_input_tokens and cache_read_input_tokens on the usage object. Use getattr(u, "cache_creation_input_tokens", 0) or 0 (as shown in the POC) to guard against both missing attributes and None values during a library upgrade.
5. Counting Tokens Before the Cache Write
If you use client.messages.count_tokens() to pre-flight a request, the token count does not account for the caching overhead. A cached block costs 1.25x on write. Include that in your cost model if you are building a budget guardrail.
6. Assuming Cache Hits Across Different Accounts
The cache is scoped to your API key, the specific model, and the exact token sequence. A multi-tenant platform where each tenant has their own API key gets no shared cache benefit. Each key builds its own cache entry independently.
Cost and Latency: Real Numbers
The table below shows estimated cost and relative latency across models and call types for a 3,500-token knowledge base + 100-token user question + 200-token output. The "savings vs no cache" column assumes a continuous workload where every call after the first is a cache hit.
| Model | Call type | Input cost | Cache write cost | Cache read cost | Total per call | Saving vs no-cache |
|---|---|---|---|---|---|---|
| Haiku 4.5 | Standard (no cache) | $0.00108 | n/a | n/a | $0.00406 | baseline |
| Haiku 4.5 | Cache write (first) | $0.00010 | $0.00131 | n/a | $0.00439 | n/a (overhead) |
| Haiku 4.5 | Cache read (nth) | $0.00010 | n/a | $0.000105 | $0.00318 | ~22% |
| Sonnet 4.6 | Standard (no cache) | $0.01080 | n/a | n/a | $0.04080 | baseline |
| Sonnet 4.6 | Cache write (first) | $0.00180 | $0.01309 | n/a | $0.04489 | n/a (overhead) |
| Sonnet 4.6 | Cache read (nth) | $0.00180 | n/a | $0.001047 | $0.03285 | ~80% |
| Opus 4.8 | Standard (no cache) | $0.05400 | n/a | n/a | $0.14400 | baseline |
| Opus 4.8 | Cache read (nth) | $0.00900 | n/a | $0.00525 | $0.11425 | ~79% |
Latency-wise, cache hits are measurably faster because the model skips the attention computation over the cached prefix. In practice this means 100-300ms lower time-to-first-token for a 3,500-token prefix on Sonnet, which is noticeable in interactive applications.
For a deeper look at combining caching with model routing, see Part 27 on cost optimization and routing. That article covers routing cheap queries to Haiku while routing complex queries to Sonnet, compounding the savings from this technique.
When to Use Claude Prompt Caching (and When Not To)
| Use case | Cache the prefix? | Notes |
|---|---|---|
| Customer support bot with large product FAQ | Yes, strongly | FAQ rarely changes; traffic is continuous. |
| Document Q&A within a session | Yes | Cache the document for the session, refresh on upload. |
| Code review with style guide | Yes | See Part 5 for the full pattern. |
| Contract analysis with clause library | Yes | See Part 11. |
| Hourly batch job with 2-hour gap between runs | Only with keep-alive | Cache expires; pay write cost each batch unless you keep it warm. |
| Fully dynamic prompts (every call unique) | No | No repeated prefix, no savings. |
| Very short system prompt (< 2048 tokens) | No | Below the minimum threshold; silently ignored. |
| Single one-off API call | No | You pay 1.25x with no second call to recoup the premium. |
The pattern also pairs well with Part 10 on RAG with pgvector. In a RAG pipeline you retrieve a small number of document chunks and inject them into the prompt. If your retrieval regularly surfaces the same top-N chunks (common in narrow-domain Q&A), caching the full retrieval context can cut costs significantly. If your retrieved chunks vary widely per query, caching the fixed system prompt alone still saves on that portion.
Integrating Caching into Production Applications
Cache Invalidation Strategy
Because the cache is keyed to the exact token sequence, invalidation happens automatically whenever the content changes. Your application does not need to manage a cache key; the API handles it. The practical implication: when you update your knowledge base or system prompt, the first call after the update pays the write fee automatically, and all subsequent calls in the same five-minute window hit the new cache entry.
For applications with infrequent knowledge base updates (say, a weekly product FAQ refresh), the write cost is negligible. The only time it matters is if you are updating the prompt on every single call, which is a sign that the dynamic content belongs outside the cached block.
Observability
Log cache_creation_input_tokens and cache_read_input_tokens alongside your normal token usage metrics. The ratio of cache reads to cache writes tells you how effective the cache is. A ratio above 10:1 means the cache is working well. A ratio of 1:1 or lower means either the traffic cadence is too sparse or the prefix content is changing between calls.
For a full observability setup including token cost dashboards and trace-level token attribution, see Part 28 on observability and tracing.
Combining with Streaming
Prompt caching is fully compatible with streaming. The cache hit reduces time-to-first-token; the stream then delivers the completion incrementally as normal. There is no change to the streaming interface. See Part 26 on streaming for the full streaming pattern.
Frequently Asked Questions
Does prompt caching work on all Claude models?
Yes. Cache write and cache read are supported on all three current tiers: Haiku 4.5, Sonnet 4.6, and Opus 4.8. The minimum cacheable token thresholds differ: 1,024 tokens for Haiku, and 2,048 tokens for Sonnet and Opus. Pricing multipliers (1.25x write, 0.1x read) are the same across all models; only the base input price per million tokens differs.
What exactly is the five-minute TTL? Does it restart on every call?
Yes. The five-minute TTL is a sliding window that resets each time the cached prefix is accessed. A request that hits the cache extends the TTL by another five minutes from that moment. In practice, a workload that sends one request every 30 seconds will keep the cache perpetually warm. A workload that sends one request every 10 minutes will always pay the write cost.
Can I cache tool definitions or conversation history, or only system prompts?
You can cache any content block, including tool definitions passed in the tools parameter and user/assistant turns in the messages array, as long as the cached block comes at the start of the prompt sequence. The most common patterns are caching the system prompt, caching a large user-provided document at the start of a session, and caching a growing conversation history. You cannot cache a block in the middle of a message list.
How do I verify a cache hit happened?
Read msg.usage.cache_read_input_tokens. If it is greater than zero, you had a cache hit. On a miss (first call or after TTL expiry), cache_creation_input_tokens will be greater than zero and cache_read_input_tokens will be zero. The POC code in this article prints both values after every call so you can confirm the behavior directly.
Does caching affect the quality or determinism of the response?
No. A cache hit means the model skips recomputing the KV attention over the cached prefix, but the cached computation is identical to what it would have computed fresh. The model output is statistically equivalent. Temperature settings and any other sampling parameters still apply normally to the uncached (new) portion of the prompt.
What happens if the same prefix is sent from two different API keys?
Each API key has its own cache namespace. Two different keys sending the same prefix do not share a cache entry. Each key builds and maintains its own cache independently. In a multi-tenant application where each tenant uses a shared API key, all tenants share the same cache namespace. If each tenant has their own key, they do not benefit from each other's cache writes.
Is there a cost to checking whether a cache entry exists?
No. The cache lookup is part of normal request processing. You do not pay anything extra to attempt a cache lookup. If the entry is found, you pay the reduced cache-read rate. If it is not found, the block is processed normally at the standard input rate (or you can mark it with cache_control to write it to cache at 1.25x for future calls).
Browse all articles in the AI in Production series.