settings.json is where Claude Code stores its configuration — permissions, environment variables, hooks, the default model, a custom status line. The docs describe it in fragments scattered across several pages, which is why people keep tripping on the same three things: they can't remember which scope wins, they paste keys that belong in a different file, and they guess at the shape of permissions. This guide pulls the pieces together: the four scopes, the precedence order, the keys worth knowing, and the mistakes that silently break your config.
Two adjacent primitives live in their own files and have their own guides. If you're reaching for hooks, see the Claude Code hooks guide — the shape of a hook entry is its own topic. If you're looking for mcpServers, that key does not live in settings.json at all; see the MCP servers guide for where it actually lives.
Claude Code reads four separate settings.json files and merges them in a fixed order. Each one answers a different question: "what does IT mandate?", "what do I prefer across all my repos?", "what does this team agree on?", "what's just for me in this repo?"
| Scope | Location | Who it affects | Shared with team |
|---|---|---|---|
| Managed | Server-managed, plist / registry, or system-level managed-settings.json |
All users on the machine | Yes (deployed by IT) |
| User | ~/.claude/ directory (i.e., ~/.claude/settings.json) |
You, across all projects | No |
| Project | .claude/ in repository (i.e., .claude/settings.json) |
All collaborators | Yes (committed to git) |
| Local | .claude/settings.local.json |
You, in this repository only | No (gitignored) |
When to use each:
disableAllHooks) to every machine and doesn't want users overriding it.Managed settings have per-OS locations: /Library/Application Support/ClaudeCode/managed-settings.json on macOS, /etc/claude-code/managed-settings.json on Linux and WSL, C:\Program Files\ClaudeCode\managed-settings.json on Windows (the legacy C:\ProgramData\ClaudeCode\... path was dropped in v2.1.75). macOS MDM deployments use the com.anthropic.claudecode managed preferences domain; Windows fleets can ship JSON via the HKLM\SOFTWARE\Policies\ClaudeCode registry key under a Settings REG_SZ value. A managed-settings.d/ drop-in directory is merged alphabetically for multi-file deployments.
When the same key appears in multiple scopes, Claude Code resolves it top-down. Highest wins:
claude invocation; session-only..claude/settings.local.json..claude/settings.json.~/.claude/settings.json.Concrete example: if a permission is allow in user settings and deny in project settings, the project deny wins. Teams lock down shared repos without stomping your personal defaults in other projects. Arrays merge across scopes; objects deep-merge; scalars are overridden by the higher-precedence scope.
~/.claude.json is a separate file, not another scope. It holds theme, notification settings, editor mode, OAuth session state, MCP servers for user and local scopes, per-project state, and caches. Putting its keys into settings.json triggers a schema validation error and the config is silently ignored — this is one of the most common footguns on this surface.
A working file doesn't need much. This is enough to get useful behavior without surprises:
{
"$schema": "https://json.schemastore.org/claude-code-settings.json",
"permissions": {
"allow": [
"Bash(npm run lint)",
"Bash(npm run test *)",
"Read(~/.zshrc)"
],
"deny": [
"Bash(curl *)",
"Read(./.env)",
"Read(./.env.*)",
"Read(./secrets/**)"
]
},
"env": {
"CLAUDE_CODE_ENABLE_TELEMETRY": "1",
"OTEL_METRICS_EXPORTER": "otlp"
}
}
Field-by-field:
$schema — a reference to json.schemastore.org/claude-code-settings.json. VS Code, Cursor, and other schema-aware editors pick it up automatically to give you autocomplete on keys and inline validation on typos. It's optional but cheap.permissions.allow — rules that skip the "do you want to let Claude run this?" prompt. Match tool invocations by name and optional argument pattern.permissions.deny — rules that refuse the tool call outright. Never prompts, never runs. Good place to pre-empt anything that touches secrets or does network fetches you don't want.env — environment variables applied to every session Claude Code spawns. Good for tracing flags, API endpoints, or feature toggles you always want on.The schema has more keys than most people need. The ones that actually come up in practice:
| Key | What it controls | Example |
|---|---|---|
permissions |
Allow/ask/deny rules, extra working directories, default permission mode. See the next section for its full shape. | { "allow": ["Bash(npm test)"] } |
env |
Environment variables that will be applied to every session. | {"FOO":"bar"} |
hooks |
Configure custom commands to run at lifecycle events. See the hooks guide for the nested format. | See hooks guide |
model |
Override the default model to use for Claude Code. | "claude-sonnet-4-6" |
outputStyle |
Configure an output style to adjust the system prompt. | "Explanatory" |
statusLine |
Configure a custom status line to display context. | {"type":"command","command":"~/.claude/statusline.sh"} |
cleanupPeriodDays |
Session files older than this period are deleted at startup (default: 30 days, minimum 1). Setting to 0 is rejected with a validation error. |
20 |
attribution |
Customize attribution for git commits and pull requests. | {"commit":"🤖 Generated with Claude Code","pr":""} |
apiKeyHelper |
Custom script, executed in /bin/sh, to generate an auth value. |
/bin/generate_temp_api_key.sh |
disableAllHooks |
Disable all hooks and any custom status line. | true |
includeCoAuthoredBy is still accepted but deprecated — prefer attribution.commit, which gives you finer control over the commit and PR trailer text.
permissions is the one key worth reading closely because it's the one you'll reach for most and its sub-fields have non-obvious semantics.
| Subkey | What it does | Example |
|---|---|---|
allow |
Array of rules to allow tool use. | [ "Bash(git diff *)" ] |
ask |
Array of rules that ask for confirmation. | [ "Bash(git push *)" ] |
deny |
Array of rules that deny tool use. | [ "WebFetch", "Bash(curl *)", "Read(./.env)" ] |
additionalDirectories |
Extra working directories for file access. | [ "../docs/" ] |
defaultMode |
Default permission mode for a session. Documented values (as of 2026-04-18): default, acceptEdits, plan, auto, dontAsk, bypassPermissions. The published schema at json.schemastore.org may accept additional experimental modes — check the live settings docs if a value you see in config doesn't match this list. |
"acceptEdits" |
disableBypassPermissionsMode |
Set to "disable" to prevent bypass mode; also disables --dangerously-skip-permissions. |
"disable" |
skipDangerousModePermissionPrompt |
Skip the bypass-permissions confirmation prompt. Ignored when set in project settings (prevents untrusted repos from auto-bypassing). | true |
Rule evaluation order: deny rules first, then ask, then allow. First match wins. That means a broad allow can't accidentally unlock something a specific deny already caught. If you're wiring hooks inside the permissions model, see the hooks guide — hooks is a separate top-level key, not a subkey of permissions.
settings.json. editorMode, theme, MCP servers for local or user scope — those live in ~/.claude.json, not settings.json. When you put them in the wrong file, schema validation fails and the config is silently ignored. You won't see an obvious error, just your setting not doing anything.includeCoAuthoredBy. It's deprecated. Use attribution.commit and attribution.pr instead — you get precise control over the trailer text on both commits and PRs..claude/settings.local.json. Claude Code auto-adds this file to .gitignore when it creates it. Adding it manually to the repo breaks the "local-only override" contract and leaks your personal overrides to the whole team.settings.json while Claude Code is running. Backups are automatic (5 retained, timestamped), but the running session may use cached values until you restart. For live changes inside an interactive REPL, use the /config command instead — it picks up edits without a restart.~/.claude/settings.json for user, .claude/settings.json for project, .claude/settings.local.json for local — for the key name. If it's not there, it's not being read. This is the only source of truth for "is my key actually in a file Claude Code will load"; everything else is derived from it./config inside an interactive Claude Code REPL. Per the live docs, /config opens "a tabbed Settings interface where you can view status information and modify configuration options." Use it to see what values are in effect after precedence resolves. If a key is in a file but not reflected in /config, a higher-precedence scope is shadowing it, or the running session has a cached value and needs a restart./status for session context. Per the commands reference, /status opens the Settings interface on the Status tab — it shows version, model, account, and connectivity. Useful for confirming which model is active and which account you're authenticated against, but it is not a settings-file origin tracer.claude --help. Confirms that any flag or subcommand you're referencing actually exists on your installed version. Schema-level support for a key can lag the CLI flag that sets it.No. settings.json is for Claude Code configuration (permissions, hooks, model). ~/.claude.json stores OAuth, theme, editorMode, MCP servers for user/local scope, per-project state. Putting ~/.claude.json keys into settings.json triggers a schema validation error.
Both are in the repo, but only .claude/settings.json is committed. Claude Code auto-adds .claude/settings.local.json to .gitignore on creation. Use the local file for personal overrides; use the committed one for team-shared settings.
Managed settings always win. After that: command-line args, then local, then project, then user. So if a permission is allow in user settings and deny in project settings, the project deny wins.
No — they won't do anything. The $schema line (pointing to json.schemastore.org/claude-code-settings.json) gives you autocomplete and some inline validation in VS Code, Cursor, and other schema-aware editors, but the published schema does not warn on every unknown top-level property, so the editor alone won't reliably catch typos or made-up keys. Validate your keys against the live settings reference instead of relying on the editor.
Set "disableAllHooks": true in settings.json. This also disables any custom status line. Managed settings can enforce it organization-wide — users can't override a managed disableAllHooks: true.
settings.json is the control surface, but a real workflow needs the content that fills it — CLAUDE.md templates, slash commands, hooks patterns, allow/deny rules that match your stack. The Claude Code Starter Kit covers that content. The Cursor Rules Kit covers the same problem for teams driving from the IDE instead of the terminal.
5 CLAUDE.md templates, 10 slash commands, hooks cookbook, 20 power prompts. Pairs directly with the settings.json patterns on this page.
5 .cursorrules templates (including Agent Mode guardrails), 10 Composer prompt snippets, settings + model selection guide.
Saved you time? Tip the maker in BTC — no account, no signup, just paste.
bc1qs04leape97ner4wqa98n94l9n0gv9aa84eg4ux
Hand-built single-file games, quizzes, and visualizers — no signup, no tracking, no cost.