Why Claude Code Uses So Many Tokens (and How to Cut It)
Claude Code resends your whole conversation on every request. See what else inflates token usage, what breaks prompt caching, and the habits that cut it.

Claude Code uses a lot of tokens because every request to the model carries your whole conversation, not just the message you typed. The Claude Code costs page says it directly: the full history goes with each request, and each time Claude uses tools, another request goes out carrying that batch of tool results on top of everything before it. A one-line question in a session that's been open all day still re-sends the whole day.
Prompt caching keeps that affordable, since repeated history is billed at the cached rate rather than the full input rate. But the cache has a lifetime, and once it expires your next message reprocesses the entire context. Add project instructions that load at startup, skills that stay in context once invoked, tool output that never leaves, and background turns you didn't start, and usage climbs much faster than your typing suggests. Each cause below comes with the habit that counters it.
The whole conversation is resent on every request#
The model has no memory between calls. Each time Claude Code needs a reply, it sends the system prompt, your project instructions, the tool definitions, every earlier message, every tool call and every tool result, then reads back the next piece of output. That full transcript is what "context" means in practice.
Two things follow from that.
- Tool calls multiply requests. A single prompt that leads Claude to read six files, grep twice and run the tests isn't one request. It's a chain of requests, and each one carries everything before it plus the new tool output.
- Growth compounds. Turn 50 costs more than turn 5 even when both are one sentence, because turn 50 carries 49 turns of history.
Here's a small model of that growth. It assumes each turn adds a fixed amount of new context and totals what gets sent over a session, with and without clearing halfway through.
# Cumulative input tokens over a session where each turn adds new context.
BASE = 12_000 # system prompt, instructions, tool definitions
PER_TURN = 1_500 # new messages and tool output added each turn
TURNS = 40
def total_sent(clear_at=None):
context = BASE
sent = 0
for turn in range(1, TURNS + 1):
if clear_at and turn == clear_at:
context = BASE
context += PER_TURN
sent += context
return sent
no_clear = total_sent()
with_clear = total_sent(clear_at=20)
print(f'turns: {TURNS}, new tokens per turn: {PER_TURN:,}')
print(f'input sent over the session, no clear: {no_clear:,}')
print(f'input sent over the session, clear at 20: {with_clear:,}')
print(f'tokens saved by one clear: {no_clear - with_clear:,}')
Your real numbers will differ, but the shape won't. Total input grows roughly with the square of the turn count, so a session half as long sends far less than half the tokens.
Prompt caching, and what breaks it#
Caching is what makes the resend model workable. The prompt caching documentation describes it as resuming from a prefix: content up to the last cache breakpoint is stored, and a later request with the same prefix reads it back instead of processing it again. Claude Code re-reads your history at the cached token rate, which the pricing page's worked example shows as a small fraction of the normal input price.
The catch is that the cache expires. As of October 16, 2026, the costs page lists the lifetime as an hour on a subscription, dropping to five minutes once you're drawing on usage credits. On an API key or a cloud provider it's five minutes by default. Your first message after a break longer than that misses the cache and reprocesses the full context at the uncached rate. The Claude Code prompt caching page covers choosing the TTL yourself if you want to keep the hour while on usage credits.
A few more things that cause misses, drawn from the same documentation:
- Anything that changes the early part of the prompt. Caching is prefix based, so whatever sits after a changed section can't be reused.
- Prompts under the minimum. The minimum cacheable length is 512 tokens for Claude Fable 5.1, Opus 5.5, Sonnet 5.5 and Haiku 5.5. Shorter prompts are processed without caching and no error is returned. Claude Code sessions clear this easily, but it matters if you script the API directly.
- Parallel requests fired too early. A cache entry only becomes available after the first response begins, so concurrent requests sent before that don't hit it.
If you're on the API, the usage object tells you what happened: cache_read_input_tokens, cache_creation_input_tokens and input_tokens add up to total input. The input_tokens field alone only counts what came after the last breakpoint, so it looks misleadingly small on a cached request. On a Pro, Max, Team or Enterprise plan, the /usage breakdown flags any behavior that accounts for 10% or more of your recent usage, cache misses included, with a tip for each.
Project instructions and rules load with every session#
CLAUDE.md is loaded into the conversation at the start of every session, and the conversation is what gets resent, so a long one costs you on every turn. The Claude Code memory documentation describes a way to keep that overhead down: rules in .claude/rules/ without a paths field load unconditionally, but a path-scoped rule only loads when Claude uses Read, Write or Edit on a matching file, or views it with a Bash command that counts as a read, such as cat or head on a single file.
So instead of putting TypeScript conventions in the main file, scope them:
---
paths:
- "src/**/*.{ts,tsx}"
---
# TypeScript rules
- Prefer named exports
- No default-exported React components
Claude Code removes the frontmatter before loading the rule. Personal rules in ~/.claude/rules/ load before project rules and apply to every project on your machine, so keep those lean as well. If your repository has an AGENTS.md and no CLAUDE.md, Claude reads the AGENTS.md instead, which takes v2.1.277 or later.
The costs page also shows a short "Compact instructions" example for steering what a compaction summary keeps. A focused summary is a smaller summary:
# Compact instructions
When you are using compact, please focus on test output and code changes
Skills stay in context once invoked#
The skills documentation explains the lifecycle: when you or Claude invoke a skill, the rendered SKILL.md enters the conversation as a single message and stays there across later turns. It's never re-read, and re-invoking an identical skill adds a short "already loaded" note rather than a second copy. But if the rendered content differs, because the arguments changed or a dynamic context command produced new output, the full content is appended again.
Two habits help here:
- Stop Claude from invoking a skill on its own with
disable-model-invocation: truein its frontmatter, or "user-invocable-only" in skillOverrides. You can still call it yourself. - Turn off bundled skills you never use by setting disableBundledSkills to true, or hide a single one with "off" in skillOverrides.
Compaction has its own budget for skills. After a summary, Claude Code re-attaches the most recent invocation of each skill, keeping the first 5,000 tokens of each, within a combined 25,000-token budget filled from the most recently invoked skill backward. Older skills can be dropped entirely, so late in a long session it's worth invoking a skill again if Claude seems to have stopped following it.
Tool output stays in context, and tools cost before you call them#
Every file Claude reads and every command it runs comes back as a tool result, and that result is input on every request afterward. The pricing page lists exactly what tool use adds: the tools parameter itself (names, descriptions and schemas), tool_use blocks, tool_result blocks, and a tool-use system prompt that costs 286 tokens on Claude Opus 5.5, Sonnet 5.5 and Haiku 5.5 with the default tool choice. The schemas and that system prompt are small per request but ride along on every one.
The tool results are the part you control. A 3,000-line log pasted into context once is paid for on every turn until you clear. Concrete habits:
- Ask for the specific function or file, not "look through the repo".
- Have Claude filter output. A grep or a head on a log beats cat on the whole thing.
- Push exploration into a subagent. The costs page notes that each subagent sends its own requests on top of the main conversation, so this isn't free, but it works in its own context window, so the files it reads don't pile up in your main conversation. The attribution breakdown in /usage shows the subagent share. If you haven't set one up, the subagent file format and examples take a few minutes.
Turns you didn't start#
Several features send a full-context request while you're not typing. The costs page lists them, and each has an off switch:
| Source | What happens | What to do |
|---|---|---|
| Scheduled tasks | Fire on their interval even while the session is idle, sending your full context each time | Remove tasks you no longer need |
| Cross-session messages | A message from another session is delivered as a new turn when this one is idle | Set crossSessionInbound to hold |
| Goal check-ins | While background work keeps a goal waiting, Claude is asked to check on it even when idle, at most three idle check-ins per goal since v2.1.246 | Set CLAUDE_CODE_GOAL_CHECKIN_MINUTES to 0 |
| Agent teammates | Each active teammate keeps consuming tokens until it exits | Have them exit when their work is done |
| Dynamic workflows | Every agent a workflow spawns sends its own requests | Keep workflows small; check the attribution breakdown |
The costs page points to the settings reference for crossSessionInbound. If you're unsure which of the several settings files to edit, the settings.json locations guide sorts that out. Idle goal check-ins require v2.1.236 or later, and before v2.1.246 they were uncapped, so an older build can run up more of them.
What a token costs, and why caching changes the math#
As of October 16, 2026, the pricing page lists these rates per million tokens. All four models have a 1M-token context window, which is also why a session can grow so large before anything forces a compaction.
| Model | Input | Output |
|---|---|---|
| Claude Fable 5.1 | $10 | $50 |
| Claude Opus 5.5 | $4 | $20 |
| Claude Sonnet 5.5 | $2 | $10 |
| Claude Haiku 5.5 | From $0.10 | From $0.50 |
The pricing page's worked example for a one-hour Claude Opus 5.5 session prices cache reads at the input rate times 0.05. This reproduces that calculation so you can plug in your own session's numbers, and it adds two rows showing what one cache miss on a large context looks like next to the same request served from cache:
// Cost of one Opus 5.5 request, with and without cache reads.
const INPUT_PER_MTOK = 4;
const OUTPUT_PER_MTOK = 20;
const CACHE_READ_MULTIPLIER = 0.05;
function cost(inputTokens, outputTokens, cacheReadTokens = 0) {
const uncached = inputTokens - cacheReadTokens;
const inputCost = (uncached * INPUT_PER_MTOK) / 1e6;
const cacheCost = (cacheReadTokens * INPUT_PER_MTOK * CACHE_READ_MULTIPLIER) / 1e6;
const outputCost = (outputTokens * OUTPUT_PER_MTOK) / 1e6;
return inputCost + cacheCost + outputCost;
}
console.log(`50k in, 15k out, no cache: $${cost(50_000, 15_000).toFixed(3)}`);
console.log(`50k in, 15k out, 40k cache reads: $${cost(50_000, 15_000, 40_000).toFixed(3)}`);
console.log(`200k context, cache expired: $${cost(200_000, 500).toFixed(3)}`);
console.log(`200k context, served from cache: $${cost(200_000, 500, 199_000).toFixed(3)}`);
One more thing from the same page: Claude 4.7 and later models use a newer tokenizer that produces approximately 30 percent more tokens for the same text than earlier models. If your counts jumped after a model change with no change in how you work, that's part of the explanation. For teams on the API, the costs page points to workspace spend limits in the Claude Console as the place to cap total Claude Code spend.
Common mistakes that burn tokens#
- One session for everything. Switching from a bug fix to a docs edit in the same session drags the bug's file reads along. Running /clear between unrelated tasks costs nothing.
- Compacting instead of clearing. /compact reads the whole conversation it summarizes, so compacting a large context is itself a large request. It's the right call when you need continuity and the wrong one when you don't.
- Returning after lunch and continuing as if nothing changed. The cache is gone after an hour on a subscription, five minutes on an API key. On Pro and Max, when you resume a large session after a long break, Claude Code offers to resume from a summary. Take it.
- Letting Claude cat whole files and logs. That output lives in context until you clear.
- A CLAUDE.md that reads like a wiki. Unconditional content is paid on every turn. Scope it with paths.
- Forgetting teammates, scheduled tasks and goals. They keep sending full-context turns while you're away.
- Hitting the plan limit and assuming it's a bug. If a session just stopped, what happens when the usage limit is reached and when it resets covers the reset window rather than the token math.
Quick reference#
- Run /usage on Pro, Max, Team or Enterprise to see which behaviors account for 10% or more of recent usage.
- Use /clear between unrelated tasks. It's free.
- Use /compact only when continuity matters. It's a full-context request.
- Accept the resume-from-summary offer after a long break on Pro or Max.
- Keep CLAUDE.md short and move file-type guidance into path-scoped rules.
- Give compaction short instructions on what to keep (test output, code changes).
- Set
disable-model-invocation: trueon skills Claude shouldn't pick up on its own. - Filter tool output with grep or head instead of reading whole files.
- Use subagents for broad exploration so the reads stay out of the main context.
- Set crossSessionInbound to hold and CLAUDE_CODE_GOAL_CHECKIN_MINUTES to 0 if you don't want idle turns.
- On the API, add cache_read_input_tokens, cache_creation_input_tokens and input_tokens to get the real input total.
Quick answers
Why does Claude Code use so many tokens?
Every request carries the whole conversation, including every tool result so far, and each tool call triggers another request. Prompt caching reduces the price of that repeated history, but a cache miss after a break reprocesses all of it at the full rate.
Why is my Claude Code using so many tokens when I barely typed anything?
Usually it's a long session, a cache miss after a break, or background turns from scheduled tasks, cross-session messages, goal check-ins, teammates or subagents. On Pro, Max, Team or Enterprise, /usage flags any behavior responsible for 10% or more of recent usage.
Does /compact save tokens?
It shrinks later requests, but the compaction itself reads the whole conversation and is a large request. When you don't need the history, /clear is free and saves more.
What does tokens mean here?
Tokens are the pieces of text a model processes, and both what you send and what Claude writes back are billed by token. The same text can tokenize differently by model: Claude 4.7 and later use a tokenizer that produces approximately 30 percent more tokens than earlier models.
Did this solve it?
One tap. No account.
Sorry about that. What was missing?
from 0 readers
Saved you an hour? Send a tip.
USDC or ETH on Base, Ethereum, Arbitrum and more. Keeps the notes free and the examples running.
Network
0xc783bc5c3fa14cEC3f09A22284bC91C5AF0d59e1
On a computer? Scan the code with your phone wallet, or copy the address.
Pick the network your wallet or exchange uses. USDC works on all six; ETH on Base, Ethereum, Arbitrum and Optimism. Don't send on Tron or Solana: this address doesn't exist there. Tips are optional and unlock nothing; every guide stays free.
Discussion
Start the discussion
Next note