Claude Code Token Usage: Reduce Cost Without Losing Quality
What tokens actually cost in a Claude Code session
Claude Code bills on tokens: input tokens (everything Claude reads) and output tokens (everything Claude writes). The pricing varies by model.
Current Anthropic API pricing (as of mid-2026):
| Model | Input (per 1M tokens) | Output (per 1M tokens) | Cache write | Cache read |
|---|---|---|---|---|
| Claude Haiku 4.5 | $0.80 | $4.00 | $1.00 | $0.08 |
| Claude Sonnet 4.5 | $3.00 | $15.00 | $3.75 | $0.30 |
| Claude Opus 4 | $15.00 | $75.00 | $18.75 | $1.50 |
Output tokens cost 5x more than input tokens on every model. This means code generation sessions are significantly more expensive than analysis sessions for the same total token count.
A rough cost breakdown for a typical developer session using Sonnet:
| Activity | Input tokens | Output tokens | Cost |
|---|---|---|---|
| Reading CLAUDE.md (200 lines) | 2,500 | 0 | $0.0075 |
| Reading 5 source files (avg 200 lines each) | 12,500 | 0 | $0.0375 |
| 20 conversational exchanges | 8,000 | 4,000 | $0.084 |
| Generating 3 new files (avg 150 lines) | 0 | 9,000 | $0.135 |
| Modifying 4 existing files | 8,000 | 12,000 | $0.204 |
| Total | 31,000 | 25,000 | ~$0.47 |
A 47-cent session is not alarming in isolation. But a developer running 5-10 such sessions per day on Sonnet, or using Opus for the same work, faces meaningfully different economics:
- 5 sessions/day on Sonnet: ~$2.35/day, ~$47/month
- 5 sessions/day on Opus: ~$11.75/day, ~$235/month
The difference between "I barely notice the bill" and "this needs active management" is mostly which model you use and how much code generation you do.
Model routing: the highest-leverage optimisation
The single most effective cost reduction technique is using the right model for each task type. Opus, Sonnet, and Haiku are not interchangeable. Each has a quality level that is appropriate for certain tasks and overkill for others.
Haiku (cheapest, fastest): Simple, well-defined tasks with clear inputs and outputs.
- Generate a TypeScript interface from a JSON schema
- Write a unit test for a function with known inputs/outputs
- Add JSDoc comments to existing functions
- Simple refactors: rename a variable across a file, add a missing return type
- Boilerplate generation: new route handler from a template, CRUD operations for a defined schema
Sonnet (balanced): The workhorse for most development work.
- Feature implementation with moderate complexity
- Debugging with context spread across 3-5 files
- Code review of a pull request
- Writing integration tests
- Explaining how a system works and suggesting improvements
- Most CLAUDE.md-guided code generation
Opus (most capable, most expensive): Tasks that genuinely require sophisticated reasoning.
- Designing a complex system architecture from scratch
- Diagnosing a subtle concurrency bug or race condition
- Refactoring a tangled, legacy codebase with unclear dependencies
- Writing a security review that requires adversarial thinking
- Cross-cutting concerns that require holding many constraints simultaneously
The practical routing heuristic: start with Sonnet. If you find yourself re-prompting because the output misses something subtle, switch to Opus for that specific task. If Sonnet is consistently generating correct output for simple tasks, try Haiku.
In Claude Code, switching models:
# Check current model
claude config get model
# Switch to Haiku for a simple task
claude config set model claude-haiku-4-5
# Switch back to Sonnet for the main work
claude config set model claude-sonnet-4-5
You can also set the model per-session using the --model flag:
# Start a Haiku session for a specific batch task
claude --model claude-haiku-4-5 "Generate unit tests for all functions in src/lib/utils.ts"
Prompt caching: the biggest cost reduction you are probably not using
Anthropic's prompt caching feature allows Claude to cache large, repetitive portions of the input and reuse them across requests at a dramatically lower cost. Cache reads cost approximately 10x less than uncached input reads.
For Claude Code specifically, prompt caching applies to:
Large CLAUDE.md files: If your CLAUDE.md is 200+ lines and stays the same across requests in a session, Claude can cache it after the first read and charge only cache-read prices for subsequent references.
Large source files that are read multiple times: A 500-line schema file that Claude references 5 times in a session costs 5x the uncached input price without caching, and approximately 1.5x (one uncached read + four cached reads) with caching.
System prompts in automated pipelines: If you are using the Claude API programmatically with a static system prompt (CLAUDE.md equivalent), enabling prompt caching on the system prompt dramatically reduces costs in high-volume automation.
Enabling prompt caching via the API:
import Anthropic from '@anthropic-ai/sdk';
const client = new Anthropic();
const response = await client.messages.create({
model: 'claude-sonnet-4-5',
max_tokens: 4096,
system: [
{
type: 'text',
text: yourLargeSystemPrompt,
cache_control: { type: 'ephemeral' } // Cache this block
}
],
messages: [
{
role: 'user',
content: userMessage
}
]
});
The cache_control: { type: 'ephemeral' } annotation marks the block for caching. Cached blocks are stored for 5 minutes (ephemeral cache). If the same block appears again within 5 minutes, Anthropic returns the cached version at cache-read pricing.
For a CLAUDE.md with 3,000 tokens running 20 requests per session:
- Without caching: 20 * 3,000 = 60,000 input tokens at $3.00/M on Sonnet = $0.18
- With caching: 1 cache write (3,000 tokens) + 19 cache reads (3,000 tokens each) at $3.75/M + $0.30/M = $0.011 + $0.017 = $0.028
That is an 85% reduction on the CLAUDE.md portion alone. For large codebases where Claude repeatedly references the same large files, the savings compound.
In Claude Code itself, prompt caching is handled automatically for the CLAUDE.md content when the session sends multiple requests with the same system content. You do not need to do anything special; the Claude API applies caching where it can. The explicit API usage above is for custom tooling built on top of the Anthropic API.
CLAUDE.md token costs: compact but powerful
Every token in CLAUDE.md is an input token on every request in every session. A 10,000-token CLAUDE.md (roughly 750 lines of Markdown) costs $0.03 per request on Sonnet without caching. At 50 requests per session, that is $1.50 per session just for the CLAUDE.md.
Optimise CLAUDE.md for density: express the most important rules in the fewest words.
Before (verbose):
## Error handling
When you are writing any function that might throw an error or that performs
an asynchronous operation, you should always make sure to wrap the code in
appropriate error handling. This means using try/catch blocks or handling
the error in the Promise chain. Do not leave errors unhandled because this
can cause the application to crash unexpectedly.
After (dense):
## Error handling
ALWAYS: wrap async operations in try/catch or handle the Promise rejection.
NEVER: leave unhandled errors (they crash the process).
Pattern: throw new AppError('CODE', 'message', statusCode) from src/lib/errors.ts
The verbose version: 63 words. The dense version: 27 words. Both express the same constraint. The dense version costs 57% fewer tokens on every single request for the rest of the project's life.
For reference information that is not needed on every request, use file pointers instead of inline content:
## Database schema
Reference: src/lib/drizzle/schema.ts
Human-readable summary: docs/schema-summary.md
Read the summary unless you need exact column definitions.
Claude reads docs/schema-summary.md only when relevant to the current task, rather than loading the full schema on every request.
Measuring token usage per session
The Claude Code CLI provides usage statistics per session. Run claude with the --verbose flag to see token counts:
claude --verbose
Or check usage in the Anthropic Console at console.anthropic.com under Usage. The Console shows per-day and per-model token counts with cost breakdowns.
For programmatic cost tracking in automated pipelines:
const response = await client.messages.create({ ... });
console.log({
inputTokens: response.usage.input_tokens,
outputTokens: response.usage.output_tokens,
cacheCreationTokens: response.usage.cache_creation_input_tokens,
cacheReadTokens: response.usage.cache_read_input_tokens,
estimatedCost: (
(response.usage.input_tokens / 1_000_000) * 3.00 +
(response.usage.output_tokens / 1_000_000) * 15.00 +
(response.usage.cache_creation_input_tokens / 1_000_000) * 3.75 +
(response.usage.cache_read_input_tokens / 1_000_000) * 0.30
).toFixed(4)
});
Logging this for every request in an automated pipeline makes it easy to identify expensive operations and track the effect of optimisations.
Reducing output tokens: the expensive half
Output tokens cost 5x more than input tokens. Strategies to reduce them without sacrificing quality:
Request specific outputs, not complete files. Instead of asking Claude to output an entire 300-line file after adding one function, ask it to output only the new function. You apply the function to the file yourself.
Before:
Add a validateEmail() function to src/lib/validators.ts and output the full updated file.
After:
Write just the validateEmail() function to add to src/lib/validators.ts.
I'll add it to the file myself after the closing brace of validatePhone().
The first version generates 300 lines (the full file). The second generates 15 lines (just the function). On Sonnet at $15/M output tokens: 300 lines costs roughly $0.045, 15 lines costs roughly $0.0023.
Use terse output mode for boilerplate. When generating repetitive boilerplate (test stubs, CRUD routes, TypeScript interfaces from a schema), ask Claude to be concise:
Generate unit test stubs for all exported functions in src/lib/validators.ts.
Output only the test structure and empty test bodies, no example assertions.
I will fill in the assertions.
Batch related requests instead of sequential ones. Five separate requests each producing 100 tokens of output cost more than one request producing 500 tokens, because each request also carries input overhead (CLAUDE.md, conversational context, the question itself).
Instead of:
# Request 1
Add a validateEmail() function.
# Request 2
Add a validatePhone() function.
# Request 3
Add a validateUrl() function.
Use:
# Single request
Add validateEmail(), validatePhone(), and validateUrl() to src/lib/validators.ts.
Output all three functions together.
The single-request pattern also tends to produce more consistent functions because Claude writes them in one context rather than three separate ones.
File read discipline: where input tokens get wasted
The most common source of unnecessary input tokens is Claude re-reading the same large files multiple times within a session. Each re-read is a full input token cost for the file contents.
Patterns that cause excessive re-reads:
Asking Claude to verify its own previous output. After generating code, Claude often wants to re-read the file to confirm the integration. Avoid triggering this with phrases like "make sure it fits the existing code."
Asking about a file mid-session without providing context. "How does the auth middleware work?" causes Claude to re-read
src/middleware/auth.ts. Better: "Given the auth middleware we read earlier..."Switching between multiple large files repeatedly. Working on file A, then B, then A again, then B again costs 4 file reads instead of 2.
A discipline that reduces unnecessary reads:
## File read policy (CLAUDE.md)
- Read each source file at most once per session unless it was modified
- If you need information from a file you already read this session, use your
memory of it; do not re-read unless the file was modified since you read it
- When starting a new sub-task that requires specific files, list all the files
you need and read them all at once before starting
This CLAUDE.md rule explicitly instructs Claude to use its in-context memory rather than defaulting to re-reads.
The 40-60% cost reduction in practice
Combining model routing, prompt caching, CLAUDE.md density, output minimisation, and file-read discipline consistently produces 40-60% cost reduction in real development sessions. Here is what the numbers look like before and after:
Before optimisation (Sonnet, no caching, verbose patterns):
- 50 requests/session
- Average 2,000 input tokens per request (including repeated CLAUDE.md reads)
- Average 1,200 output tokens per request (full file outputs)
- Total: 100,000 input + 60,000 output = $0.30 + $0.90 = $1.20/session
After optimisation (Sonnet with caching, dense CLAUDE.md, targeted outputs):
- 50 requests/session
- CLAUDE.md cached after first read: 2,500 tokens cached, 300 average uncached input tokens
- Average output tokens: 600 per request (targeted outputs, not full files)
- Total input: 1 cache write (2,500) + 49 cache reads (2,500) + 50 * 300 uncached = roughly $0.052
- Total output: 50 * 600 = 30,000 output tokens = $0.45
- $0.50/session (58% reduction)
The biggest single contributor to the reduction is switching from full-file outputs to targeted outputs. That alone accounts for roughly half the savings. Model routing contributes more dramatically if you were using Opus for tasks that Sonnet handles well.
Quick-reference cost optimisation checklist
Before starting a heavy Claude Code session, run through this list:
- Is the model set correctly for this task type? (
claude config get model) - Is CLAUDE.md under 100 lines and density-optimised?
- Does CLAUDE.md use file pointers for large reference content?
- Am I asking for targeted outputs (specific functions/methods) rather than full files?
- Are related requests batched into single prompts?
- If using the API programmatically, is
cache_controlenabled on system prompts?
The last item on the list is the one most developers miss. Prompt caching in API-based automation delivers the largest cost reduction with the least change to workflow. If you are building any tooling on top of Claude Code or the Anthropic API that sends the same system prompt repeatedly, enabling caching is the highest-return optimisation available.
For the full picture on how context management interacts with token costs (re-reads, compaction, session length), see Claude Code context management. For memory setup that keeps CLAUDE.md compact and efficient, see Claude Code memory setup.
Get Claudify. Optimised CLAUDE.md templates that deliver maximum context in minimum tokens, with prompt caching patterns and model routing guides for every task type.
More like this
Ready to upgrade your Claude Code setup?
Get Claudify