This appendix lists the key user-configurable environment variables in Claude Code v2.1.88. Grouped by functional domain, only variables affecting user-visible behavior are listed; internal telemetry and platform detection variables are omitted.
Environment variables are just one facet of Claude Code's configuration system. The complete configuration system is composed of 6 layers of sources, merged from lowest to highest priority — later sources override earlier ones. Understanding this priority chain is crucial for diagnosing "why isn't my setting taking effect."
Configuration sources are defined in restored-src/src/utils/settings/constants.ts:7-22, and the merge logic is implemented in the loadSettingsFromDisk() function at restored-src/src/utils/settings/settings.ts:644-796:
Priority
Source ID
File Path / Source
Description
0 (lowest)
pluginSettings
Plugin-provided base settings
Only includes whitelisted fields (e.g., agent), serves as the base layer for all file sources
1
userSettings
~/.claude/settings.json
User global settings, applies across all projects
2
projectSettings
$PROJECT/.claude/settings.json
Project shared settings, committed to version control
3
localSettings
$PROJECT/.claude/settings.local.json
Project local settings, automatically added to .gitignore
4
flagSettings
--settings CLI parameter + SDK inline settings
Temporary overrides passed via command line or SDK
Merging uses lodash's mergeWith for deep merge, with a custom merger defined at restored-src/src/utils/settings/settings.ts:538-547:
Objects: Recursively merged, later source fields override earlier ones
Arrays: Merged and deduplicated (mergeArrays), not replaced — this means permissions.allow rules from multiple layers accumulate
undefined values: Interpreted as "delete this key" in updateSettingsForSource (restored-src/src/utils/settings/settings.ts:482-486)
This array merge semantic is particularly important: if a user allows a tool in userSettings and allows another tool in projectSettings, the final permissions.allow list includes both. This enables multi-layer permission configurations to stack rather than override each other.
Policy settings (policySettings) have their own internal priority chain, using a "first source with content wins" strategy, implemented at restored-src/src/utils/settings/settings.ts:322-345:
Sub-priority
Source
Description
1 (highest)
Remote Managed Settings
Enterprise policy cache synced from API
2
MDM Native Policies (HKLM / macOS plist)
System-level policies read via plutil or reg query
Drop-in directory support, merged in alphabetical order
4 (lowest)
HKCU User Policies (Windows only)
User-level registry settings
Note that policy settings merge differently from other sources: the four sub-sources within policies are in a competitive relationship (first one wins), while policies as a whole are in an additive relationship with other sources (deep merged to the top of the configuration chain).
Configuration loading has a two-layer caching mechanism (restored-src/src/utils/settings/settingsCache.ts):
File-level cache: parseSettingsFile() caches the parsed result of each file, avoiding repeated JSON parsing
Session-level cache: getSettingsWithErrors() caches the merged final result, reused throughout the session
Caches are uniformly invalidated via resetSettingsCache() — triggered when the user modifies settings through the /config command or updateSettingsForSource(). Settings file change detection is handled by restored-src/src/utils/settings/changeDetector.ts, which drives React component re-rendering through file system watching.
When a setting "isn't taking effect," troubleshoot in this order:
Confirm the source: Use the /config command to view the current effective configuration and source annotations
Check priority: Is a higher-priority source overriding your setting? policySettings is the strongest override
Check array merging: Permission rules are additive — if a deny rule appears in a higher-priority source, a lower-priority allow cannot override it
Check caching: After modifying .json files within the same session, the configuration may still be cached — restart the session or use /config to trigger a refresh