Tips for Token Optimisation in Claude Code
Introduction
If you use Claude Code daily, you have already paid the context-window tax: every file Claude reads, every command output, and every message in the conversation sits in the context window and is sent to the model again on every turn.
If you are on API billing, that repeated input is a direct per-token cost; on a Pro or Max subscription, the same usage counts against your plan's usage limits. A debugging session or a codebase exploration can consume tens of thousands of tokens on its own.
The docs also warn that Claude's performance tends to degrade as the context fills - it can start "forgetting" earlier instructions and making more mistakes. So trimming context waste is worth doing for focus as much as for usage.
The good news: most token waste comes from a few habits, and Claude Code ships with built-in commands to find and fix it. In this post, we will see nine practical tips to reduce token usage in Claude Code - measuring usage, clearing and compacting context, keeping CLAUDE.md lean, delegating to subagents, taming MCP servers, and preprocessing with hooks.
Everything below is verified against the official Claude Code documentation as of October 2026. Claude Code changes fast, so check the linked docs pages if a command behaves differently for you.
Measure first: /usage and /context
You cannot optimize what you cannot see. Claude Code has two built-in commands for this:
/usageshows the Session block with token usage and an estimated cost for the current session (the dollar figure is computed locally at list price and is meant for API users; Pro/Max subscribers see plan usage bars instead). After the first API response, it also shows a Prompt cache line, for example14 requests ยท 91% of input tokens from cache- more on caching in Tip 9./contextshows a live breakdown of what is filling your context right now, by category, with optimization suggestions - including whichCLAUDE.mdand memory files were loaded.
On a subscription plan, /usage also shows an attribution breakdown - what share of your recent usage went to skills, subagents, plugins, and individual MCP servers - plus recommendations, one per row, such as:
25% Trim ~/code/api/CLAUDE.md ยท 49k tokens per request
When the footer shows a hint like f to fix 2 of 3, pressing f makes Claude Code apply the recommendations it can (this shortcut requires Claude Code v2.1.305 or later).
There is also /insights, which writes an HTML report on how you work - friction points, misunderstood requests, and suggestions - based on your recent sessions on that machine.
Clear between tasks: /clear
This is the cheapest token saver there is. Stale context wastes tokens on every subsequent message, so run /clear whenever you switch to unrelated work.
Two habits that make clearing painless:
- Run
/renamebefore clearing so you can find the session later, and/resumeto return to it. - If you have corrected Claude more than twice on the same issue in one session, the context is cluttered with failed approaches. The docs' advice: run
/clearand start fresh with a more specific prompt that includes what you learned. A clean session with a better prompt almost always outperforms a long session full of accumulated corrections.
Note that /clear also resets the session cost counters in /usage, so the next session's total starts at $0.
Compact with a focus: /compact
When a session grows long, Claude Code compacts automatically as you approach the context limit: it summarizes the conversation history and keeps working. You can do better than the automatic pass by compacting on your own terms:
/compact Focus on the auth bug fix and the list of modified files
With instructions, the summary keeps what you choose instead of what the automatic pass guesses is important.
You can also set standing compaction instructions in your project's CLAUDE.md:
# Compact instructions When you are using compact, please focus on test output and code changes
More options from the current docs:
/rewindlets you select a message checkpoint and choose Summarize from here (condenses everything after that point) or Summarize up to here (condenses earlier messages, keeping recent ones in full)./autocompactwith a token count (for example/autocompact 500k) sets how full the context window gets before the automatic pass runs.
Keep CLAUDE.md lean
CLAUDE.md is loaded at the start of every conversation, so every line in it costs tokens on every message you send - forever, until you remove it. The docs' test for each line is simple: "Would removing this cause Claude to make mistakes?" If not, cut it.
Bloated CLAUDE.md files are doubly expensive: they burn tokens AND cause Claude to ignore your actual instructions.
Practical ways to slim it down:
- Run
/doctor- its checkup proposes trims for a checked-inCLAUDE.md, cutting content Claude can derive from the codebase itself (directory layouts, dependency lists, architecture overviews) and keeping the parts it cannot (pitfalls, rationale, conventions that differ from tool defaults). - Move knowledge that is only relevant sometimes into skills (
.claude/skills/). Skill descriptions load at startup, but the full body loads only when the skill is invoked - domain knowledge on demand instead of in every conversation. - Use path-scoped rules for instructions that apply only to certain files; they load on demand alongside matching files.
- If you use the auto-memory file
MEMORY.md, note that only its first 200 lines (or 25KB) load at startup - keep the index concise and move detail into topic files.
One more detail worth knowing: @path imports in CLAUDE.md help organization but do NOT reduce context, because imported files load together with the file that imports them.
Send heavy reading to subagents
Subagents run in their own context window with their own system prompt and return only a summary to your main conversation. That makes them the right tool whenever a side task would flood your context with search results, logs, or file contents you will never reference again - codebase exploration and research are the classic cases.
Claude Code's built-in Explore subagent exists exactly for this: Claude delegates searching and understanding the codebase to it, and the large file reads stay out of your main conversation.
Two cost controls for subagents:
- For simple subagent tasks, set
model: haikuin the subagent configuration to run it on a lower-cost model. Defining a user or project subagent named Explore overrides the built-in one while keeping its model field. - Keep subagent description fields short. All descriptions load into context so Claude can decide when to delegate, and Claude Code warns at startup when the combined custom descriptions exceed 15,000 tokens. Move detail into the subagent's system prompt, which loads only when that subagent runs.
One honest caveat: a subagent sends its own API requests, which count toward the same usage limits as your main conversation. Subagents save main-context tokens (the ones you repay on every turn); they do not make the work itself free.
Tame your MCP servers
MCP servers are the quiet token leak in many setups. The good news first: in current Claude Code, MCP tool definitions are deferred by default - only tool names and server instructions enter your context until Claude actually uses a specific tool.
Still, every connected server adds overhead, and the docs recommend two moves:
- Prefer CLI tools where they exist. Tools like
gh,aws,gcloud, andsentry-cliare more context-efficient than MCP servers because they add no per-tool listing at all - Claude just runs the CLI commands. - Disable servers you are not actively using. Run
/mcpto see the configured servers and toggle them off per project; the configuration is kept for when you need them back.
To find out whether a server earns its keep, check the per-server attribution in /usage (Tip 1) - an MCP server's share counts only the requests that actually consumed one of its tool results.
Pick the right model for the job
Model choice is the biggest per-token lever you have: Sonnet handles most coding tasks well and costs less than Opus. Reserve Opus for complex architectural decisions or multi-step reasoning. Switch mid-session with /model, or set a default in /config. Note that switching to Opus also applies to subagents that inherit your session's model.
For simple subagent work, specify model: haiku in the subagent configuration (Tip 5).
If you routinely hit context limits on big tasks, the docs also list models with a 1 million token context window (Sonnet 4.6 and later, Haiku 5.5, Opus 4.6 and later), selectable as [1m] variants. A bigger window raises the ceiling; the tips above lower the bill.
Preprocess with hooks
Hooks run scripts automatically at points in Claude's workflow, and unlike CLAUDE.md instructions they are deterministic - the action always happens. A PreToolUse hook can filter command output before it ever reaches the context.
The docs' example: instead of Claude reading a 10,000-line log to find errors, a hook greps for ERROR and returns only matching lines - tens of thousands of tokens become a few hundred.
Here is the docs' pattern, adapted to also catch Maven and Gradle test runs. Add the hook to your settings.json:
{ "hooks" : { "PreToolUse" : [ { "matcher" : "Bash" , "hooks" : [ { "type" : "command" , "command" : "~/.claude/hooks/filter-test-output.sh" } ] } ] } }
Then save this as ~/.claude/hooks/filter-test-output.sh and make it executable (chmod +x):
#!/bin/bash
input = $( cat )
cmd = $( echo " $input " | jq -r '.tool_input.command' )
# If running tests, filter to show only failures
pattern = '^(npm test|pytest|go test|mvn test|./mvnw test|./gradlew test)( [^;&|<>`$#\\[:cntrl:]]*)?$'
if [[ " $cmd " = ~ $pattern ]] ; then
filtered_cmd = "f= \$ (mktemp); $cmd > \"\$ f \" 2>&1; s= \$ ?; grep -A 5 -E '(FAIL|ERROR|error:)' \"\$ f \" | head -100; echo \" [exit \$ s - full output at \$ f] \" ; exit \$ s"
echo " $input " | jq --arg filtered " $filtered_cmd " \
'{hookSpecificOutput: {hookEventName: "PreToolUse", updatedInput: (.tool_input + {command: $filtered})}}'
else
echo "{}"
fi
When the command is a test run, the hook rewrites it so Claude sees only the failure lines; anything else passes through unchanged.
A word on doing this safely, because the naive version of this idea can mislead Claude:
- Preserve the exit status. A pipeline's exit code is its last command's, so
cmd | grep | headwould report success whenevergrepandheadsucceed - even when the tests themselves failed. That is how Claude ends up believing broken tests are green. The script above saves the original exit code (s=$?) and exits with it, so a failing run still looks like a failure. (Verified locally: failing tests exit 1, a crash with no matching output still exits 134.) - Keep the full output reachable.
grep -A 5andhead -100can cut a stack trace's root cause, and merging stderr into the filter (2>&1) drops any error text that does not match the pattern - compiler errors in an unusual format, OOM crashes, "Aborted". The script writes the complete output to a temp file and prints its path, so Claude can read the full log when the filtered view is not enough. - Only simple commands get filtered. The pattern's argument part rejects
|,;,&,$, backticks and other shell metacharacters, so anything complex (pipelines, command substitution) runs exactly as written instead of being mangled by the rewrite. - Filtering is lossy by design. Treat the filtered view as a first look. For security-sensitive output (dependency audits, secret scanners), do not filter at all - a hidden warning is worse than a big context.
The same pattern works for build logs or any chatty, non-sensitive command you run often - apply the safety points above each time.
Small habits that add up
A few one-liners from the docs that are easy to adopt:
- Use
/btwfor side questions. The answer never enters the conversation history, so you can check a detail without growing (and paying for) the context on every following turn. - Be specific in prompts. "fix the login bug" sends Claude exploring; "login fails after session timeout - check the auth flow in src/auth/, especially token refresh, and write a failing test first" goes straight to the files that matter. Specific prompts mean fewer exploratory file reads.
- Install code intelligence plugins for typed languages. A single "go to definition" call replaces a grep plus reading multiple candidate files, and the language server reports type errors after edits without a compiler run.
- Let prompt caching work for you. Claude Code automatically caches repeated content like the system prompt, and the Prompt cache (main) line in
/usagetells you the share of input tokens served from cache - in the docs' example session, 91% - so you can see it working.
Summary
- Measure first:
/usagefor cost and attribution,/contextfor what is filling the window,/insightsfor patterns. /clearbetween unrelated tasks (/renamefirst,/resumeto return); compact long sessions with focused instructions.- Keep
CLAUDE.mdlean - every line rides along on every message. Move on-demand knowledge to skills and path-scoped rules. - Delegate heavy reading to subagents, run simple ones on
haiku, and keep their descriptions short. - Prefer CLI tools over MCP servers, and disable servers you are not using.
- Match the model to the task: Sonnet by default, Opus for the hard parts, Haiku for simple subagents.
- Preprocess noisy command output with
PreToolUsehooks, and use/btwfor questions that do not need to stay in context.
Token optimization in Claude Code is really context optimization. Trimming irrelevant context reduces the input you send on each turn - on API billing that is direct cost saved, and on a subscription it stretches your usage limits further. And since the docs note that performance degrades as context fills, a leaner context can als
Comments
No comments yet. Start the discussion.