Logo Vincent
Back to all posts

Claude Code settings.json Explained (1): Where Config Files Live and Who Wins

Claude
Claude Code settings.json Explained (1): Where Config Files Live and Who Wins

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:

LevelNameFile path
1 (lowest)User settings~/.claude/settings.json
2Project settings.claude/settings.json
3Local settings.claude/settings.local.json
4CLI flag--settings <path or JSON>
5 (highest)Admin policymanaged-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)

PlatformPath
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

PlatformPath
macOS/Library/Application Support/ClaudeCode/managed-settings.json
Linux/etc/claude-code/managed-settings.json
WindowsC:\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

GoalWhich 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 enforcementmanaged-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 will go deeper into specific configuration fields.

More Articles

© 2026 vincentqiao.com . All rights reserved.