settings.json
Status: 🟩 COMPLETE (🟦 LIVING) Last updated: 2026-06-19 Plain-English tagline: The config file where Claude Code’s behavior is tuned — permissions, env vars, hooks, MCP servers, model preference. A well-tuned settings file is the difference between a smooth session and constant friction.
In plain English
settings.json is Claude Code’s main configuration file. It controls:
- Which tools can run without asking you (permissions)
- Environment variables Claude sees
- Hooks (what runs on events)
- MCP servers (external tool integrations)
- The default model
- Notification preferences
- Telemetry settings
- And more
There are several scopes the file can live at:
| Scope | Path | Applies to |
|---|---|---|
| User (global) | ~/.claude/settings.json | All projects |
| Project (shared) | <project>/.claude/settings.json | This project, all team members |
| Project (local) | <project>/.claude/settings.local.json | This project, this machine only |
| Enterprise (managed) | OS-specific | All users, all projects on this machine |
Lower scopes override higher ones. Project-local beats project-shared beats global beats enterprise.
The two you’ll touch most: user (global) for your standing preferences, and project (local) for project-specific quirks you don’t want to commit.
Why it matters
Without tuning, Claude Code is conservative — it asks for permission on almost everything. That’s safe but tedious. After 100 prompts of “Approve Read /Users/georg/project/file.md?”, the friction destroys your flow.
Tuning settings well:
- Auto-approves the safe stuff you do constantly
- Asks for the risky stuff so you stay in the loop
- Hard-blocks the dangerous stuff that should never run
- Pre-configures env vars so you don’t have to set them each session
- Sets your default model so every session starts where you want
Five minutes of settings tuning saves hours of friction over the following month.
The settings.json shape
A reasonably full example:
{
"$schema": "https://json.schemastore.org/claude-code-settings.json",
"model": "claude-opus-4-7",
"permissions": {
"allow": [
"Read(*)",
"Glob(*)",
"Grep(*)",
"Bash(npm run *)",
"Bash(git status *)",
"Bash(git diff *)",
"Bash(git log *)"
],
"ask": [
"Bash(*)",
"Write(*)",
"Edit(*)"
],
"deny": [
"Bash(rm -rf /*)",
"Bash(curl * | sh)",
"Read(~/.ssh/*)"
]
},
"env": {
"ANTHROPIC_API_KEY": "${ANTHROPIC_API_KEY}",
"EDITOR": "code --wait"
},
"hooks": {
"Stop": [
{
"hooks": [
{ "type": "command", "command": "powershell -Command \"[System.Console]::Beep(800, 200)\"" }
]
}
]
},
"mcpServers": {
"filesystem": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-filesystem", "~/projects"]
}
},
"outputStyle": "default",
"notifications": {
"onTurn": true,
"onPermission": true
}
}Let’s walk through each section.
Permissions — the highest-leverage tuning
The three buckets:
| Bucket | Behavior |
|---|---|
allow | Auto-approved without asking |
ask | Prompts you each time |
deny | Blocked outright; not even askable |
Each entry is a pattern that matches tool name + arguments. Examples:
"Read(*)"— allow any Read call"Bash(npm run *)"— allownpm run dev,npm run build, etc., but not other Bash"Bash(git status*)"— allowgit status,git status -s, etc."Write(~/.ssh/*)"— would block writing into SSH keys folder"Bash(rm -rf /*)"— denyrm -rfof anything starting from root
Strategy: build allow up over time. Start conservative. When you find yourself re-approving the same kind of call repeatedly, add it to allow. Over weeks, your allow list becomes a tailored set of “safe routine operations” specific to how you work.
Strategy: use deny sparingly. A small deny list of truly destructive patterns is high-value. A long deny list becomes a maintenance burden.
The env section
Set environment variables that Claude sees:
"env": {
"ANTHROPIC_API_KEY": "${ANTHROPIC_API_KEY}",
"DATABASE_URL": "${DATABASE_URL}",
"EDITOR": "code --wait"
}The ${VAR} syntax reads from your shell environment — so you don’t put secrets directly in settings.json (which might get committed).
This is useful for:
- API keys that tools call (Anthropic, OpenAI, Linear, etc.)
- Editor / pager preferences
- Tool-specific config (e.g.
NODE_OPTIONS,DEBUG=true)
Hooks — covered in detail elsewhere
The hooks section configures event-driven shell commands. See the Hooks entry for the full picture.
Quick reference: each event maps to an array of matcher-grouped hook lists. Most common are PreToolUse (block or validate), PostToolUse (log, format), and Stop (notify).
MCP servers
The mcpServers section configures which MCP servers Claude Code connects to:
"mcpServers": {
"filesystem": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-filesystem", "~/projects"],
"env": {
"ALLOWED_DIRS": "~/projects,~/Documents"
}
},
"github": {
"command": "node",
"args": ["/path/to/github-mcp-server/dist/index.js"],
"env": {
"GITHUB_TOKEN": "${GITHUB_TOKEN}"
}
}
}Each server entry tells Claude how to launch it (command + args) and what env vars to set. After this, the server’s tools become available as if they were native.
For most users, MCP servers are easier to add via the claude mcp add <name> CLI command, which updates settings.json for you.
Model selection
"model": "claude-opus-4-7"Sets the default model for the session. You can override per-session with /model.
For new projects, choose based on the work: Opus for serious dev, Sonnet for routine, Haiku for trivial / high-volume.
The system prompt indicated your current model is claude-opus-4-7; you can pin to a newer version when you upgrade.
Output style
"outputStyle": "default"Controls how Claude formats responses. Built-in options usually include default, concise, verbose. Plugins can add custom output styles.
For most uses, default is fine. If you want shorter responses always, the appropriate style helps.
Notifications
"notifications": {
"onTurn": true,
"onPermission": true,
"onError": true
}Controls when Claude pings the OS for your attention. Useful for long-running tasks where you walk away.
These overlap with hooks (you can configure a Stop hook to do the same thing). Use whichever is cleaner for your case.
Telemetry and privacy
There are usually settings for opt-in telemetry, conversation logging, etc. Defaults are typically privacy-respecting (no telemetry without consent). Check the official docs for the current shape.
A pattern: start global, override per-project
For your setup:
Global (~/.claude/settings.json):
- Your preferred model
- Standing permissions (the routine safe operations)
- Standing env vars
- Stop notifications
Project-local (<project>/.claude/settings.local.json):
- Project-specific Bash patterns (e.g. allow
Bash(supabase *)only in projects that use Supabase) - Project-specific MCP servers (e.g. a Supabase MCP only in Bible Quest)
- Project-specific hooks (e.g. run prettier after edits)
This split keeps your global setup minimal and lets each project add its own quirks without polluting other projects.
A concrete example: a tuned settings file for your stack
For a developer who uses Next.js + Supabase + Vercel on Windows:
{
"model": "claude-opus-4-7",
"permissions": {
"allow": [
"Read(*)",
"Glob(*)",
"Grep(*)",
"Bash(npm run *)",
"Bash(npm install)",
"Bash(npm test*)",
"Bash(git status*)",
"Bash(git diff*)",
"Bash(git log*)",
"Bash(git branch*)",
"Bash(vercel ls*)",
"Bash(vercel logs*)",
"Bash(supabase status)"
],
"ask": [
"Bash(git commit*)",
"Bash(git push*)",
"Bash(vercel*)",
"Bash(supabase *)",
"Write(*)",
"Edit(*)"
],
"deny": [
"Bash(rm -rf /*)",
"Bash(curl * | sh)",
"Bash(*.env*)",
"Read(~/.ssh/*)",
"Read(*.env)"
]
},
"env": {
"ANTHROPIC_API_KEY": "${ANTHROPIC_API_KEY}"
},
"hooks": {
"Stop": [
{
"hooks": [
{ "type": "command", "command": "powershell -Command \"[System.Console]::Beep(800, 200)\"" }
]
}
]
}
}This auto-approves all the routine read operations, npm scripts, and git inspection. It asks for git commit/push and any vercel/supabase command. It hard-blocks anything that could exfiltrate keys or destroy the filesystem.
After a session with these settings, you’ll notice dramatically fewer prompts without sacrificing safety.
The /update-config skill
The update-config skill (you have it installed) helps modify settings.json without hand-editing JSON. Useful examples:
- “Allow Bash npm commands” → adds the right pattern
- “Move permission to user settings” → moves between scopes
- “Set DEBUG=true” → adds env var
- “When Claude stops, show notification” → adds a Stop hook
For non-coders especially, /update-config is much safer than editing JSON directly.
Common gotchas
-
JSON syntax errors break Claude Code. Missing commas, trailing commas (not allowed in JSON), unclosed quotes. Use a JSON-validating editor. If Claude Code fails to start, suspect a JSON error in settings.
-
Pattern syntax is glob-style, not regex.
Bash(git *)matchesgit anything. It does NOT matchxgit something. Asterisk matches any chars within the same arg; double-asterisk varies. Test patterns deliberately. -
allowpatterns must be precise. A too-broadBash(*)in allow defeats the point. Be specific. -
askis the default. If a tool call doesn’t matchallowordeny, it’sask. You don’t have to list patterns underaskunless you want documentation. -
Settings don’t reload mid-session. Most changes take effect next session. Some changes (model switch) can be made via
/modelmid-session. -
Local settings (
settings.local.json) shouldn’t be committed. They’re for your machine. The project-sharedsettings.jsonis the one teams collaborate on. Use.gitignoreforsettings.local.json. -
Permissions are pattern-matched against tool call as serialized. Quirky strings (file paths with spaces, special chars) may not match obvious patterns. Test by trying.
-
MCP servers in settings can be slow to start. Each one adds startup time. Disable the ones you don’t currently use.
-
Env vars from settings don’t expand
~to home. Use absolute paths or shell-expanded variables. -
Newer Claude Code versions add new settings. Check the official docs occasionally to see what’s available.
-
Enterprise-managed settings override yours. If you’re on a corporate-managed machine, some settings may be locked. Look for a managed-settings location specific to your OS.
See also
- Claude Code deep dive 🟩 🟦
- Hooks 🟩 — configured here
- Slash commands 🟩 —
/update-configis the safer editor - Plugins 🟩 — plugins update this file
- The memory system 🟩 — orthogonal but complementary