Blog · September 22, 2026 · 10 min read
Claude Code Environment Variables: The Groups That Actually Matter
Most people meet Claude Code environment variables the same way: something misbehaves, they search the exact variable name someone mentioned in a thread, and they set it without ever seeing the surrounding map. That works right up until two variables interact, or until one you set in your shell is silently overridden by a settings file.
This is the map. Not all 130-odd variables — the official environment variables reference is the place for the complete list — but the groups that actually come up, plus the rules about precedence and value formats that cause most of the confusion.
First: where to put them
You have two options, and they behave differently.
Your shell — exported from .zshrc, .bashrc or similar. Claude Code reads shell variables at startup, so changes take effect the next time you launch claude.
A settings file — under the env key in a settings.json. Claude Code reads these directly from the file, so they apply no matter how claude was launched, and a running session picks up new and changed values when you save the file. The exception is anything that reads its configuration once at startup, such as OpenTelemetry, which keeps its startup values until you relaunch.
The scopes are ~/.claude/settings.json for you everywhere, .claude/settings.json for everyone on the project and checked into source control, and .claude/settings.local.json for you in this project only.
The precedence rule that catches everyone
When the same variable is set in both your shell and a settings file env block, the settings file wins. Claude Code writes each env entry into the process environment, replacing whatever the shell handed it.
That is the opposite of what a lot of people assume, and it is the single most common reason a variable "does not work". If you exported something in your shell profile and nothing changed, check whether a project settings file is setting the same key.
There is a related trap: in a settings file you can set a variable but you cannot remove one. To neutralise a variable you cannot unset — say a stale provider selection exported by a shell profile you do not control — set it to an empty string in the env block. Claude Code treats the empty value as unset for provider selection, though subprocesses still inherit the empty value.
Between settings files, env values follow normal settings precedence, so a managed (admin-deployed) entry overrides the same variable in user or project settings.
Value formats, and the 1e6 bug worth knowing about
Numeric variables — timeouts, token budgets, retry counts — accept scientific notation and digit separators as well as plain digits. Claude Code reads 2e3 as 2000 and 64_000 as 64000.
This matters historically: before v2.1.211, those spellings could silently set a much smaller value. 1e6 would set a timeout to 1. If you have an old config lying around with scientific notation in it and you have ever wondered why a timeout behaved bizarrely, that is a candidate. A few variables take plain digits only, and their rows say so.
For on/off variables, 1 or true turns the behaviour on and 0 or false turns it off, in any casing. But a handful read only whether you set them at all, so any non-empty value including 0 turns the behaviour on, and you turn it off by unsetting the variable. Those include CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC, DISABLE_TELEMETRY and DISABLE_ERROR_REPORTING. Setting DISABLE_TELEMETRY=0 does not enable telemetry — it disables it.
Background tasks and long-running work
This group generates a surprising amount of search traffic, mostly because the variable names are long and people encounter them in error messages rather than in docs.
CLAUDE_CODE_DISABLE_BACKGROUND_TASKS— set to1to disable all background task functionality, including therun_in_backgroundparameter on Bash and subagent tools, auto-backgrounding, and the Ctrl+B shortcut. Covered in detail in our guide to disabling background tasks.CLAUDE_CODE_DISABLE_BG_SHELL_PRESSURE_REAP— set to1to stop Claude Code terminating background shell commands under memory pressure. By default, on macOS and Linux, it terminates background shells when the OS reports critical memory pressure and the session has been idle for 30 minutes with no turn or subagent running. Windows has no memory-pressure signal, so it has no effect there. We wrote that one up separately.CLAUDE_AUTO_BACKGROUND_TASKS— force-enable automatic backgrounding of long-running agent tasks, which moves subagents to the background after roughly two minutes.CLAUDE_CODE_MAX_CONCURRENT_SUBAGENTS— how many subagents can run in one session before the Agent tool refuses to spawn another (default 20).
Bash timeouts and output limits
If Claude Code keeps killing a build or a test suite partway through, this is the group you want.
BASH_DEFAULT_TIMEOUT_MS— default timeout for long-running bash commands. Default is 120000, or 2 minutes.BASH_MAX_TIMEOUT_MS— the maximum timeout the model is allowed to set. Default is 600000, or 10 minutes. The effective ceiling is the larger of this andBASH_DEFAULT_TIMEOUT_MS, which is a detail worth re-reading if you raise only one of them and nothing changes.BASH_MAX_OUTPUT_LENGTH— how many characters of bash output Claude Code reads back into a result. Default 30000, maximum 150000. If you set thebashOutputMaxCharssetting, the variable is ignored entirely.API_TIMEOUT_MS— timeout for API requests. Default 600000.
Thinking and context window
These are the ones most often set for the wrong reason.
CLAUDE_CODE_DISABLE_THINKING=1 omits the thinking parameter from API requests entirely. The docs are explicit that this is a compatibility option for proxies and gateways that reject the parameter — not a way to turn thinking off. On models that think by default, omitting the parameter means the model may still think. To actually disable extended thinking on the Anthropic API, MAX_THINKING_TOKENS=0 is the documented route.
CLAUDE_CODE_DISABLE_ADAPTIVE_THINKING=1 is narrower: it falls back to the fixed thinking budget controlled by MAX_THINKING_TOKENS on the models where adaptive reasoning is optional.
On the context side, CLAUDE_AUTOCOMPACT_PCT_OVERRIDE sets the percentage of the auto-compact window at which compaction triggers, and CLAUDE_CODE_AUTO_COMPACT_WINDOW sets that window in tokens (100000 to 1000000, plain integers only). Both are more useful than people expect for long sessions — see our context management guide for when to reach for them.
Notifications and attention
Two worth knowing if you run Claude Code unattended:
CLAUDE_CODE_DISABLE_NOTIFICATION_PRESENCE_CHECK— set to1to send the desktop notification even while you are typing in or focused on the terminal. By default Claude Code suppresses it when it thinks you are already watching, which is sensible until you are watching a different pane.CLAUDE_AFK_TIMEOUT_MSandCLAUDE_AFK_COUNTDOWN_MS— how long an unanswered question dialog waits before auto-continuing without you, and how long before the on-screen countdown appears. Auto-continue is off by default.
Both of these are the local, best-effort layer. If the reason you care is that you have walked away from the machine entirely, terminal notifications are the wrong tool regardless of how you configure them — that is the gap phone notifications exist to cover.
Turning off outbound traffic
In locked-down environments, CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC is the big hammer. Set to any non-empty value it disables auto-updates, telemetry, error reporting, the /feedback command, release notes, PR and MR status badge checks, and availability checks.
Two caveats. It also disables feature-flag fetching, which quietly changes which features are available to you — so if something stops appearing after you set it, that is the likely cause. And it does not cover official plugin marketplace auto-install, which needs CLAUDE_CODE_DISABLE_OFFICIAL_MARKETPLACE_AUTOINSTALL separately.
A sane starting point
If you want one config rather than a tour, this covers most real complaints — long builds getting killed, truncated output, and background shells disappearing on a memory-constrained laptop:
{
"env": {
"BASH_DEFAULT_TIMEOUT_MS": "300000",
"BASH_MAX_TIMEOUT_MS": "900000",
"BASH_MAX_OUTPUT_LENGTH": "100000",
"CLAUDE_CODE_DISABLE_BG_SHELL_PRESSURE_REAP": "1"
}
}Put it in ~/.claude/settings.json if it is a preference, or .claude/settings.json if it is a property of the project — a repo whose test suite genuinely takes eight minutes should say so in the repo, not in every contributor's dotfiles.
When not to set any of this
An honest caveat to close on. Most of these variables exist to work around a specific, diagnosed problem. Setting a pile of them speculatively because a thread recommended it is how you end up with a config nobody can reason about, and with behaviour that diverges from every guide and every colleague.
Change one thing, confirm it fixed the thing you were actually seeing, and leave the rest alone. Version-gated variables in particular — a number of these require a specific Claude Code version or later — fail silently rather than loudly when your version is older, which makes a speculative config extremely hard to debug later.
Keep reading
Claude Code Tips and Tricks: 12 Ways to Use Claude Code Effectively
8 min read
Claude Code Multiple Sessions: How to Run Agents in Parallel Without Losing Track
6 min read
A Claude Code Workflow That Doesn't Involve Watching the Terminal
5 min read
Claude Code Hooks: A Practical Guide to Automating Your Agent Workflow
7 min read
Claude Code Auto Mode: Fewer Permission Prompts Without Living Dangerously
7 min read
Claude Code Subagents: How to Delegate Work to Specialized Agents
7 min read
Claude Code Context Management: Treat the Context Window Like a Budget
6 min read
Per-Subagent Model Selection: Route the Grunt Work Down, Keep the Judgment Up Top
7 min read
Skills and Plugins: How to Teach Claude Code Your Way of Working
7 min read
Claude Code Background Tasks: Run Long Commands Without Blocking Your Session
6 min read
Codex CLI Notifications: How to Get a Ding When Codex Is Done or Needs Input
7 min read
Cursor Notification When Done: Every Way to Get Notified When Cursor Finishes
6 min read
Claude Code Notifications: How to Get Notified When Claude Code Finishes or Needs Your Input
6 min read
Want to Be Notified When Claude Responds? How Claude Notifications Work on Web, Desktop, and Mobile
5 min read
Claude Code Notification Scripts: Copy-Paste Recipes for Every Platform
6 min read
Get a Ding the Moment Codex Needs Your Response
6 min read
Get Notified the Moment Claude Code Is Waiting for Your Input
6 min read
“Notifications Are Turned Off for Claude” — Here Is the Fix
6 min read
Codex Sound When Done: Make Codex CLI Play a Sound When It Finishes
6 min read
terminal-notifier + Claude Code: Native macOS Alerts When Your Agent Finishes
6 min read
Gemini CLI Notifications: How to Get a Sound or Alert When Gemini Finishes
6 min read
Get Claude Code Notifications on Your Phone
6 min read
Claude Code Remote Control, Explained
7 min read
preferredNotifChannel: Claude Code's Built-In Notification Setting
6 min read
Claude Code Notifications in tmux and Over SSH
7 min read
Claude Code Effort Levels: Why Your Setting Keeps Getting Ignored
8 min read
Codex vs Claude Code Notifications: How Each One Tells You It Is Done
8 min read
Claude Code Notifications Not Working: A Diagnostic Checklist
8 min read
Claude Code Notifications Inside Your Editor's Terminal
7 min read
CLAUDE_CODE_DISABLE_BACKGROUND_TASKS Explained
7 min read
CLAUDE_CODE_DISABLE_BG_SHELL_PRESSURE_REAP Explained
8 min read
Cursor Alerts Explained: Every Alert Cursor Raises, and How to Control Them
7 min read