The Five-Layer Config Cascade: How Claude Code Resolves Settings
Claude Code resolves configuration through five layers — from enterprise-managed policies down to your personal user settings. Higher layers win over lower ones, but arrays merge instead of replace. This article walks through each layer, what it controls, and how to think about override scenarios.
Quick Reference
- →Five layers in order (highest wins): Managed → CLI flags → Local project → Shared project → User global
- →Managed settings are enterprise-deployed and cannot be overridden by anything
- →CLI flags are session-scoped — they don't persist to settings.json
- →Local project (.claude/settings.local.json) is gitignored — personal per-project overrides
- →Shared project (.claude/settings.json) is committed to git — team-wide defaults
- →User global (~/.claude/settings.json) is the personal fallback for all projects
- →Array settings (permissions.allow) merge across layers — they don't replace each other
- →CLAUDE.md files follow a separate hierarchy from settings.json files
In this article
Why Five Layers?
A single configuration file would force everyone — enterprise IT, team leads, individual developers — to agree on every setting. That doesn't work in practice. An enterprise needs to enforce security policies that no developer can override. A team needs to share project-specific defaults. An individual needs personal preferences that don't pollute the team's shared config.
The five-layer cascade solves this by giving each concern its own layer with a clear precedence order. Each layer can only override layers below it — IT policies always win, personal preferences are always the last resort.
settings.json files control permissions, model selection, and behavioral toggles. CLAUDE.md files control what Claude knows — context, conventions, architecture. These are separate systems. This article covers settings.json. See the Configuration Mastery series for CLAUDE.md.
The Five Layers in Order
| Priority | Layer | Location | Who controls it | Persists? |
|---|---|---|---|---|
| 1 (highest) | Managed | OS-level system directory | Enterprise IT / MDM | Yes |
| 2 | CLI flags | Runtime flags (--model, --permission-mode) | You, at startup | No (session only) |
| 3 | Local project | .claude/settings.local.json | You (gitignored) | Yes |
| 4 | Shared project | .claude/settings.json | Team (committed to git) | Yes |
| 5 (lowest) | User global | ~/.claude/settings.json | You (personal global) | Yes |
The golden rule: a higher-priority layer always wins over a lower-priority layer for the same setting. If the shared project config sets the model to Sonnet and you set your user global to Opus, Sonnet wins because shared project (layer 4) is higher priority than user global (layer 5).
What Each Layer Controls
Layer 1 — Managed (Enterprise)
Deployed by IT via MDM or OS policy. Lives in system directories: /Library/Application Support/ClaudeCode/ (macOS), /etc/claude-code/ (Linux), C:\Program Files\ClaudeCode\ (Windows). Supports managed-settings.json and a managed-settings.d/ drop-in directory. Cannot be overridden by any user-level setting. Used to enforce security policies: blocking certain tools, requiring specific permission modes, preventing model changes.
Layer 2 — CLI Flags
Passed at startup: claude --model claude-opus-4-7, --permission-mode plan, etc. These are session-scoped — they don't write to any settings.json. They override everything except managed settings for the duration of that session only.
Layer 3 — Local Project (.claude/settings.local.json)
Per-project personal overrides. Should be in .gitignore — this file is for your personal settings on this specific project. Use it for: personal API key references, local path overrides, experimental settings you're testing before proposing to the team.
Layer 4 — Shared Project (.claude/settings.json)
The team's shared project configuration. Committed to git — everyone on the team inherits these settings. Use it for: project-specific allowed commands, team model preferences, project-specific permission allowlists, hooks that all team members should run.
Layer 5 — User Global (~/.claude/settings.json)
Your personal default settings that apply to every project. The fallback when no higher layer specifies a setting. Use it for: personal model preferences, personal permission defaults, your default hooks.
The Array Merge Exception
Most settings follow the 'highest layer wins' rule. But array-valued settings — most importantly permissions.allow and permissions.deny — merge across all layers rather than replacing each other. This is an important nuance.
permissions.deny arrays also merge across layers. If managed settings deny a tool and your user settings also deny another tool, both denials are in effect. You cannot use a lower-priority layer to un-deny something a higher-priority layer denied.
Practical Override Scenarios
Here are concrete examples of how the cascade resolves in practice:
| Scenario | Which layer wins | Resolution |
|---|---|---|
| IT requires Sonnet, you prefer Opus in user global | Managed (Layer 1) | Sonnet is used — IT policy cannot be overridden |
| Team sets model to Sonnet in settings.json, you start with --model opus | CLI flag (Layer 2) | Opus is used for this session only — next session defaults to Sonnet |
| Team settings.json allows npm run test, your user global allows git log | Both apply (array merge) | Both commands are allowed — arrays from all layers merge |
| You set a local override in settings.local.json, team has settings.json | Local project (Layer 3) | Your local override wins for settings that conflict |
Best Practices
Do
- ✓Add .claude/settings.local.json to your .gitignore — personal overrides should not be committed
- ✓Use the shared project settings.json to establish team-wide permission allowlists
- ✓Use CLI flags for temporary session overrides rather than modifying settings.json
- ✓Use the user global settings for personal defaults that apply to all your projects
- ✓Document unusual managed settings in your team's README — developers won't know why settings seem locked
Don’t
- ✗Don't put personal model preferences in the shared project settings.json — use your user global
- ✗Don't assume deny settings in one layer can be removed by another — denials from higher layers are permanent
- ✗Don't mistake CLAUDE.md hierarchy for settings.json hierarchy — they are separate systems
- ✗Don't use CLI flags as a permanent override — they don't persist between sessions
Key Takeaways
- ✓Five layers: Managed > CLI flags > Local project > Shared project > User global
- ✓Higher priority layers override lower ones — except array settings, which merge
- ✓Local project (.claude/settings.local.json) should be gitignored — it's for personal use
- ✓Shared project (.claude/settings.json) is committed to git — affects the whole team
- ✓Managed settings cannot be overridden by any developer — enterprise IT controls them
Video on this topic
Claude Code Config Cascade: Which Setting Wins?
tiktok