Home / Extending: skills, MCP, subagents, hooks, plugins
settings.json in depth
Five levels of settings.json follow one another from strongest to weakest, a scalar key common to two files is decided by the highest-priority level, but most lists, including permissions.allow and permissions.deny, merge across levels instead of overwriting each other.
A project settings.json overrides the user's on a scalar key that both files define, and five levels follow one another before reaching this result (source code.claude.com/docs/en/settings, accessed on 2026-09-02).
Five levels, only one wins by default
From strongest to weakest: managed settings, set by an MDM or by the claude.ai console; the --settings option passed on the command line, valid for a single session; .claude/settings.local.json, private to the machine, never shared via git; .claude/settings.json, shared via git with the rest of the team on this project; and finally ~/.claude/settings.json, set once for every project opened on this machine. On a simple key present at two levels at once, the higher-ranking one wins entirely, the weaker level is not read. Managed settings stay out of reach of editing from the workstation, set by an organisation, whereas the other four levels are plain text files that anyone can open and edit directly.
Lists merge, except for four keys
The rule changes as soon as a key holds a list. permissions.allow and permissions.deny, among others, merge across levels: an entry set at user level stays active even when the project adds another one alongside it. Four keys escape this merging, each following its own rule rather than a single one. fallbackModel takes the entire value from the highest-priority level that defines it. modelPicker takes the entire value from the highest priority among managed settings, --settings and the user settings, and simply ignores the key if it is only set at project or local level. availableModels, when managed settings define it, applies as is and ignores whatever the user, project or local level add, and does not merge across several managed sources either. modelSettings is resolved model by model, with effortLevel, each entry specifying itself which file applies to which model.
{
"permissions": {
"allow": ["Bash(npm test)"],
"deny": []
},
"env": {
"NODE_ENV": "development"
}
}
The env block follows the same rule
The env block inserted in a settings file is an ordinary key that follows the same five levels as the rest of the file, but most of its values, like the permissions.allow rules, only take effect once each team member has trusted the project's folder. A shell environment variable is not a level in this stack: when a behaviour has both a variable and a settings key, which of the two applies is decided pair by pair, not by level, ANTHROPIC_MODEL exported in the shell winning, for instance, over the model key in any file, whereas ANTHROPIC_DEFAULT_MODEL only applies if no file sets model.
This hierarchy makes full sense as soon as a hook comes into play: the declaration of an event, like the one described in hook events, from trigger to message, also lives in this same file, and follows exactly the same order of priority between project and personal machine.
Five precedence levels in settings.json, from strongest to weakest
Four keys with no merging across settings.json levels
A developer adds the entry Bash(npm test) to permissions.allow in her project's .claude/settings.json file. Her machine's ~/.claude/settings.json file already carries the entry Bash(git log) in the same permissions.allow array. She then opens a new Claude Code session in this project and runs both commands.
Write, in one sentence, what this situation establishes, and in one sentence what it does not establish.
What this establishes: In this session, the two entries set at different levels, project and user, were honoured together by permissions.allow.
What this does not establish: That a key like fallbackModel or modelSettings, defined at the same two levels, would have behaved the same way in this session.
The three most common miscalibrations
- Too broad This result proves that every key in settings.json, without exception, merges this way across the five precedence levels.
- Too narrow This result proves nothing, since only a single pair of commands was observed in a single session.
- Off the mark This result shows that this project's .claude/settings.json file is committed to the git repository shared by the rest of the team.
- Five precedence levels follow one another in settings.json: managed settings, --settings command line, local project settings, shared project settings, user settings, from strongest to weakest.
- A shared project settings.json takes priority over the user's as soon as the same scalar key appears in both files.
- Most lists, including permissions.allow and permissions.deny, merge across levels instead of overwriting one another.
- Four keys are an exception to this merging, fallbackModel, modelPicker, availableModels and modelSettings, each following its own rule: modelPicker, for instance, simply ignores the key set at project or local level, rather than falling back to it.
- The env block follows the file's five levels but waits for the folder to be trusted for most of its values, and a shell variable is not a level in this stack: its precedence against a settings key is decided pair by pair.
Open or create your current project's .claude/settings.json file, and add an explicit entry in permissions.allow for a command you have been manually approving for several days in this project, then start a new session and check that the confirmation prompt no longer appears.
These points depend on an interface or a rule that may have changed since this was written. Check them on your own screen before relying on them.
- The list of four keys exempted from merging across levels may grow with a future version of Claude Code, to be rechecked at https://code.claude.com/docs/en/settings before basing a critical setting on this behaviour.
Every datable claim in this lesson links here to the public text behind it. A source that does not open proves nothing.
- Anthropic, Claude Code, settings.json settings reference consultée le 2026-09-02