Claude Code · Lesson 19

Settings & Configuration

settings.json is the control panel for Claude Code — choose the model, restrict tools, inject environment variables, and fine-tune permissions without ever editing a flag again.

Model SelectionPermission RulesEnv VarsNetwork ProxyConfig Scopes

Why Bother with Settings?

Out of the box, Claude Code makes sensible choices — but your project may need something different. Maybe you want Claude to always use a specific model for cost reasons, prevent it from ever touching production credentials, or auto-inject environment variables from a shared CI profile. That's what settings.json is for.

🤖
Model
Pin claude-opus-4, haiku-3-5, or any available model
🔒
Permissions
Allow, deny, or prompt for each tool category
🌿
Env Vars
Inject variables that Claude sees on every run
🌐
Proxy
Route traffic through a corporate HTTP proxy

Configuration Scopes

Settings are read from four places. Higher entries in the table override lower ones — so a local setting beats a project setting, which beats a user setting.

ScopeFileCommitted?Who uses it
ManagedInjected by your platform / MDMN/AEnterprise admins only
Local.claude/settings.local.jsonNo — gitignoredYour private overrides
Project.claude/settings.jsonYes — shared with teamTeam-wide rules
User~/.claude/settings.jsonNoPersonal preferences
ℹ️ Info:Precedence (highest → lowest): Managed → Local → Project → User. Values in a higher scope completely override the same key in a lower scope.

Anatomy of settings.json

Below is an original example for an inventory REST API project using Node.js. It fixes the model, restricts shell commands, and injects two env vars that Claude will see in every session.

// .claude/settings.json  (committed — shared with your team)
{
  "model": "claude-opus-4-5",

  "permissions": {
    "allow": [
      "Read(*)",
      "Write(src/**)",
      "Bash(npm run *)",
      "Bash(git status)",
      "Bash(git diff)"
    ],
    "deny": [
      "Bash(rm -rf *)",
      "Bash(curl *)",
      "Write(.env*)"
    ]
  },

  "env": {
    "NODE_ENV": "development",
    "API_VERSION": "v2"
  }
}
model

Which Claude model to use in this project

permissions.allow

Tools Claude can use without asking

permissions.deny

Tools that are always blocked

env

Key-value pairs injected into every session

Model Selection

The model key accepts any Anthropic model identifier. Set it at the user level to apply globally, or at the project level to pin a specific model for that repository.

// ~/.claude/settings.json  (user-level — your global default)
{
  "model": "claude-haiku-3-5"   // faster + cheaper for exploratory work
}

// .claude/settings.json  (project-level — overrides global default)
{
  "model": "claude-opus-4-5"    // highest quality for the production API
}
Tip:You can also switch model mid-session with /model — it respects the settings value as the default but lets you override temporarily.

Permission Rules

Each rule is a string with a tool name plus an optional glob pattern in parentheses. Rules live under three lists:

allow
Proceed without asking
deny
Always block, no override
ask
Pause and confirm each time
{
  "permissions": {
    "allow": [
      "Read(*)",             // read any file
      "Write(src/**)",       // write only inside src/
      "Bash(npm run *)",     // any npm script
      "Bash(git *)"          // any git command
    ],
    "deny": [
      "Bash(rm -rf *)",      // never delete recursively
      "Write(.env*)"         // never touch env files
    ],
    "ask": [
      "Write(package.json)"  // pause before editing deps
    ]
  }
}
⚠️ Warning:deny rules take precedence over allow rules. If a command matches both, it is blocked.

Environment Variables

Any key-value pair under env is visible to Claude in the shell environment during your session. Use this for non-secret configuration that should be consistent across the team.

{
  "env": {
    "NODE_ENV": "development",
    "API_BASE_URL": "http://localhost:3001",
    "LOG_LEVEL": "debug"
  }
}
⚠️ Warning:Do not store API keys or passwords here — settings.json is committed to git. Use settings.local.json (gitignored) for secrets, or rely on your OS keychain.

Network Proxy

If your organization routes outbound traffic through an HTTP proxy, tell Claude Code the port number. All requests to the Anthropic API will be sent via the proxy.

// ~/.claude/settings.json  (user-level — applies everywhere)
{
  "network": {
    "httpProxyPort": 8080
  }
}
ℹ️ Info:This only sets the proxy port. The proxy host is assumed to be localhost. Pair this with a local proxy tool such as Squid or Charles if you need full traffic inspection.

Worked Example: Project + Local Settings Together

The classic pattern is to commit a shared settings.json for the team and keep a private settings.local.json for your own overrides. Here's how a developer named Priya would set it up on her laptop:

.claude/settings.json — committed
{
  "model": "claude-opus-4-5",
  "permissions": {
    "allow": [
      "Read(*)",
      "Write(src/**)",
      "Bash(npm run *)",
      "Bash(git *)"
    ],
    "deny": [
      "Write(.env*)",
      "Bash(rm -rf *)"
    ]
  },
  "env": {
    "NODE_ENV": "development"
  }
}
.claude/settings.local.json — gitignored
{
  "model": "claude-haiku-3-5",
  "env": {
    "PRIYA_LAPTOP": "true",
    "LOG_LEVEL": "verbose"
  },
  "network": {
    "httpProxyPort": 3128
  }
}
What happens: Priya's local override swaps the model to haiku (cheaper for quick experiments) and adds her personal proxy. The team-wide permission rules andNODE_ENV still apply from settings.json because the local file only overrides the keys it defines.

Verifying Your Configuration

Two slash commands let you inspect the merged configuration at any time.

/config

Opens an interactive menu for viewing and editing settings.json entries live.

/status

Shows the active model, current API key status, active permissions, and project context.

Key Settings Reference

KeyTypeExampleWhat it controls
modelstring"claude-opus-4-5"Which model to use
permissions.allowstring[]["Read(*)", "Bash(git *)"]Tools allowed silently
permissions.denystring[]["Bash(rm -rf *)"]Tools always blocked
permissions.askstring[]["Write(package.json)"]Tools that need confirmation
envobject{"NODE_ENV": "dev"}Shell env vars injected per session
network.httpProxyPortnumber8080Port for outbound HTTP proxy
includeCoAuthoredBybooleanfalseSuppress Co-Authored-By git footer
hooksobject{"PostToolUse": [...]}Lifecycle event handlers

Setup Checklist

1
Create .claude/settings.json in your repo root
2
Set the model key to pin a specific Claude version
3
Add allow rules for safe, frequent commands (npm, git)
4
Add deny rules for destructive patterns (rm -rf, write .env)
5
Add safe env vars under env — never secrets
6
Create .claude/settings.local.json for personal overrides
7
Add settings.local.json to .gitignore
8
Run /status to verify the merged configuration

What's Next

Configuration is dialled in. Next: Permission Modes — controlling exactly what Claude Code is allowed to read, write, and execute.