Claude Code Settings Hierarchy: Configuring the 5-Level Override Chain
Claude Code resolves settings through a five-level hierarchy (CLI arguments → local project → project → user-global local → user-global), with managed policy settings enforced at the highest priority, and array values merged across all levels rather than replaced.
Claude Code, the AI coding assistant from Anthropic, implements a sophisticated configuration system defined in the shanraisshan/claude-code-best-practice repository. Understanding the Claude Code settings hierarchy is essential for teams who need to balance version-controlled defaults with individual developer preferences and organizational security policies.
The Five-Level Settings Override Chain
The configuration system evaluates settings from highest to lowest priority, with the first value found for any key winning. According to the source code analysis in best-practice/claude-settings.md, the hierarchy works as follows:
Level 1: Command-Line Arguments
CLI flags provide session-specific overrides that take precedence over all file-based configurations. For example, --model=sonnet immediately changes the model for that session.
claude --model=sonnet
Level 2: Local Project Settings (.claude/settings.local.json)
Personal per-project tweaks stored in .claude/settings.local.json apply to the specific repository but are git-ignored. This is ideal for individual model preferences or local environment variables.
{
"model": "haiku",
"spinnerVerbs": {
"mode": "replace",
"verbs": ["Refactoring", "Testing", "Documenting"]
}
}
Level 3: Project Settings (.claude/settings.json)
Team-wide defaults committed to version control in .claude/settings.json provide the baseline configuration for all repository collaborators.
{
"model": "opus",
"agent": "code-reviewer"
}
Level 4: User-Global Local Settings (~/.claude/settings.local.json)
Personal overrides stored in the home directory's ~/.claude/settings.local.json apply across all projects for that user.
Level 5: User-Global Settings (~/.claude/settings.json)
Global defaults in ~/.claude/settings.json serve as the fallback configuration for the entire user environment.
{
"model": "sonnet",
"env": {
"CLAUDE_AUTOCOMPACT_PCT_OVERRIDE": "70"
}
}
The Managed Policy Layer (Highest Priority)
Before evaluating the five-level chain, Claude Code checks managed-settings.json settings delivered via MDM profiles (macOS) or Windows Registry. These cannot be overridden by any user-writable configuration.
This layer enforces organizational security policies, with deny rules taking precedence over allow or ask rules according to the Settings Hierarchy documentation in best-practice/claude-settings.md.
How Array Values Merge Across Levels
Unlike scalar values where the first match wins, array-type settings are merged across all configuration levels. For example, permissions.allow accumulates entries from managed settings, project settings, and local settings.
If .claude/settings.json contains:
{
"permissions": {
"allow": ["Edit(*)", "Write(*)"]
}
}
And .claude/settings.local.json contains:
{
"permissions": {
"allow": ["Bash(git *)"]
}
}
The effective permission list becomes: ["Edit(*)", "Write(*)", "Bash(git *)"].
Summary
- Claude Code uses a five-level hierarchy (CLI args → local project → project → user-global local → user-global) with a managed policy layer at the top.
- Managed settings (
managed-settings.json) enforced via MDM or Registry cannot be overridden by users. - Array values (like
permissions.allow) are merged across all levels rather than replaced. - Scalar values follow strict priority: the first level containing the key wins.
- Use
.claude/settings.local.jsonfor personal project preferences and~/.claude/settings.local.jsonfor global personal preferences.
Frequently Asked Questions
What happens if the same setting is defined in both project and user-global configuration?
The project-level setting wins. According to the hierarchy defined in best-practice/claude-settings.md, project settings (Level 3) take precedence over user-global settings (Levels 4 and 5). The CLI argument would override both.
How do I prevent my personal settings from being committed to git?
Store personal overrides in .claude/settings.local.json or ~/.claude/settings.local.json. Both files are git-ignored by default in the repository structure, ensuring your local tweaks remain private to your machine.
Can organization policy override my CLI arguments?
Yes. The managed-settings layer (managed-settings.json) delivered via MDM profiles or Windows Registry sits above even CLI arguments in the priority chain. If an organization sets a deny rule in managed settings, it cannot be bypassed by any user configuration.
Why are my permissions not being overridden when I set them in a local file?
Array-type settings like permissions.allow are merged across all configuration levels rather than replaced. If you want to completely replace the permission list, you must use the "mode": "replace" directive within the setting, as shown with spinnerVerbs in the configuration examples.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →