Claude Code settings.json Explained (1): Where Config Files Live and Who Wins
Table of Contents
- Why the config file system matters
- Five configuration sources
- Each config file explained
- 1. User settings ~/.claude/settings.json
- 2. Project settings .claude/settings.json
- 3. Local settings .claude/settings.local.json
- 4. CLI flag --settings
- 5. Admin policy (highest priority)
- Priority rules: override vs merge
- Scalar fields: higher priority wins
- Array fields: merge and deduplicate across sources
- Which sources can be written to
- Config validation
- Quick decision guide
- Closing thoughts
Why the config file system matters
After using Claude Code for a while, you’ll want to customize things: set specific permission rules for a project, share a set of hooks across your team, or override some defaults on your own machine without committing them to git.
Behind all of this is Claude Code’s multi-layer configuration system. Understanding “which files exist” and “who overrides whom” is the prerequisite for configuring Claude Code correctly.
Five configuration sources
Claude Code’s configuration comes from five distinct sources, listed from lowest to highest priority:
| Level | Name | File path |
|---|---|---|
| 1 (lowest) | User settings | ~/.claude/settings.json |
| 2 | Project settings | .claude/settings.json |
| 3 | Local settings | .claude/settings.local.json |
| 4 | CLI flag | --settings <path or JSON> |
| 5 (highest) | Admin policy | managed-settings.json (see below) |
Higher-priority sources override lower-priority ones.
Each config file explained
1. User settings ~/.claude/settings.json
Use case: Personal preferences, applied to all projects on this machine.
This is the most commonly used config file. If you want a specific model across all projects, or want to always disable certain prompts, put it here.
{
"model": "claude-sonnet-4-6",
"cleanupPeriodDays": 60
}
This file is never committed to any git repository — it’s purely personal.
2. Project settings .claude/settings.json
Use case: Project-level shared config, used by the whole team.
Placed in the .claude/ folder at the project root, this file can be committed to git so the entire team shares the same configuration. Use it to define which bash commands are allowed in this project, or to enforce a specific response language.
{
"permissions": {
"allow": ["Bash(npm run:*)"]
},
"language": "english"
}
3. Local settings .claude/settings.local.json
Use case: Personal overrides within a project, not committed to git.
Sits in the same directory as project settings, but should not be committed to git. When Claude Code writes to this file, it automatically adds it to the project’s .gitignore.
Good for personal preference overrides — for example, using a different model in this project without affecting teammates.
{
"model": "claude-opus-4-6"
}
4. CLI flag --settings
Use case: Temporary overrides, scripted invocations, CI/CD pipelines.
Specified on the command line, this takes priority over all file-based config:
# Point to a config file
claude --settings ./my-override.json
# Pass a JSON string directly (useful in SDK calls)
claude --settings '{"model":"claude-haiku-4-5-20251001"}'
You can also use --setting-sources to restrict which sources are loaded:
# Load only user settings, ignore project and local settings
claude --setting-sources user
Note: Regardless of --setting-sources, admin policy (policySettings) and CLI flags (flagSettings) are always loaded and cannot be excluded.
5. Admin policy (highest priority)
Use case: Enterprise-wide enforcement that users cannot override.
Admin policy can be delivered in several ways, listed from highest to lowest internal priority:
① Remote policy (highest)
Pushed from the Claude.ai platform. Claude Code polls for updates periodically — no manual action required.
② MDM / registry (admin-only)
| Platform | Path |
|---|---|
| macOS (device-level) | /Library/Managed Preferences/com.anthropic.claudecode.plist |
| macOS (per-user) | /Library/Managed Preferences/<username>/com.anthropic.claudecode.plist |
| Windows (admin) | HKLM\SOFTWARE\Policies\ClaudeCode (registry value: Settings) |
macOS is managed via MDM profiles; Windows via Group Policy.
③ File-based config
| Platform | Path |
|---|---|
| macOS | /Library/Application Support/ClaudeCode/managed-settings.json |
| Linux | /etc/claude-code/managed-settings.json |
| Windows | C:\Program Files\ClaudeCode\managed-settings.json |
④ Drop-in directory
Under the same directory as the managed settings file, a managed-settings.d/ folder can contain multiple .json files. They are merged alphabetically by filename, with later files overriding earlier ones.
For example, on Linux:
/etc/claude-code/
├── managed-settings.json # base config
└── managed-settings.d/
├── 10-security.json # security team policy
├── 20-mcp-allowlist.json # platform team MCP policy
└── 30-model-restrictions.json # cost control team model limits
This design follows the systemd/sudoers drop-in convention — different teams can maintain independent policy fragments without coordinating edits to a single admin-owned file.
⑤ HKCU (Windows user registry, lowest admin priority)
HKCU\SOFTWARE\Policies\ClaudeCode — user-writable, lowest priority within the admin policy tier.
Within admin policy, Claude Code uses a first-source-wins rule: as soon as a higher-priority source has content, all lower-priority sources are completely ignored — they are not merged.
Priority rules: override vs merge
Understanding priority is one thing. But there’s a critical distinction: not all fields behave the same way when sources conflict.
Scalar fields: higher priority wins
Most ordinary fields (strings, booleans, numbers, objects) follow simple override semantics:
// User settings (lower priority)
{ "model": "claude-sonnet-4-6" }
// Project settings (higher priority)
{ "model": "claude-opus-4-6" }
// Result
{ "model": "claude-opus-4-6" }
Array fields: merge and deduplicate across sources
Array fields (such as permissions.allow[], hooks, enabledMcpjsonServers, etc.) are concatenated and deduplicated — not overridden:
// User settings
{ "permissions": { "allow": ["Bash(git:*)"] } }
// Project settings
{ "permissions": { "allow": ["Bash(npm run:*)"] } }
// Result (rules from both sources are kept)
{ "permissions": { "allow": ["Bash(git:*)", "Bash(npm run:*)"] } }
This means global permission rules in your user settings and project-level rules coexist naturally — neither clobbers the other.
Which sources can be written to
Only three sources support write operations:
- User settings (
~/.claude/settings.json) - Project settings (
.claude/settings.json) - Local settings (
.claude/settings.local.json)
--settings and admin policy are read-only — Claude Code never writes to either of these.
When you use the /config command to change a setting, it asks which source to write to (user / project / local).
Config validation
Claude Code uses Zod v4 to strictly validate all config files. A few details worth knowing:
Invalid permission rules don’t invalidate the whole file: Before schema validation, malformed permission rules are filtered out. The rest of the config still loads. This prevents a single typo in a permission rule from breaking your entire settings file.
File reads are cached: Settings are cached for the duration of the session. The cache resets automatically when files change or after a write operation.
JSON Schema support: Claude Code publishes a standard JSON Schema you can reference in your editor for autocomplete and inline validation:
{
"$schema": "https://json.schemastore.org/claude-code-settings.json",
"model": "claude-opus-4-6"
}
Quick decision guide
| Goal | Which file |
|---|---|
| Personal preferences, all projects | ~/.claude/settings.json |
| Team-shared config, committed to git | .claude/settings.json |
| Personal override, not committed | .claude/settings.local.json |
| Temporary test or one-off override | --settings '{...}' |
| Enterprise-wide enforcement | managed-settings.json or MDM |
Closing thoughts
Claude Code’s configuration system has a clear principle: personal settings belong to the person, project settings belong to the project, team settings belong to the team, and enforced settings belong to the organization.
Five layers, each with a purpose. Array merging means rules from multiple sources coexist instead of overwriting each other. Once you understand this system, you can place every config in the right file — and stop guessing why a setting “isn’t taking effect.”
The next posts in this series go deeper into specific configuration fields:
- settings.json (2) — hooks lifecycle
- settings.json (3) — permission rules
- settings.json (4) — everything else
Next step: Once config is sorted, go learn the day-to-day Claude Code commands.
Related Articles
Claude Code Agent Loop: Dissecting the Heart of an AI Coding Assistant
How does Claude Code understand your requests, invoke tools, and self-recover step by step? A source-code deep dive into the Agent Loop's core architecture — streaming responses, parallel tool execution, auto-compaction, and error recovery.
Claude Code settings.json Deep Dive (Part 2): The Permissions System
A thorough breakdown of Claude Code's permissions configuration — allow/deny/ask rule arrays, wildcard syntax, MCP tool permissions, defaultMode options, and additionalDirectories.
Claude Code settings.json Deep Dive (Part 3): The Hooks System
A thorough breakdown of Claude Code's hooks configuration — four hook types, core events (PreToolUse/PostToolUse/Stop/Notification), stdin/stdout protocol, exit code semantics, and practical examples.
Claude Code settings.json Deep Dive (4): env, Models, Auth, and Other Useful Fields
A comprehensive guide to the remaining settings.json fields in Claude Code — env variable injection, model configuration, authentication helpers, Git attribution, session cleanup, language and UI, thinking depth, auto-updates, memory system, and more.
Claude Code /agents: Give Each Task Its Own Specialist AI
Create custom sub-agents for code exploration, architecture planning, and more — each with its own role, tools, and instructions.