Course navigation
Claude CodeLesson 19 of 25

Settings & Configuration

settings.json is the control panel for Claude Code — choose the model, restrict tools, inject environment variables, and fine-tune permissions without editing flags on every run.

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.

Setting areaWhat you control
ModelPin claude-opus-4, haiku-3-5, or any available model
PermissionsAllow, deny, or prompt for each tool category
Env varsInject variables that Claude sees on every run
ProxyRoute 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
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 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"
  }
}
KeyPurpose
modelWhich Claude model to use in this project
permissions.allowTools Claude can use without asking
permissions.denyTools that are always blocked
envKey-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
}
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:

ListBehaviour
allowProceed without asking
denyAlways block, no override
askPause 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
    ]
  }
}
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"
  }
}
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
  }
}
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 and NODE_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.

CommandWhat it does
/configOpens an interactive menu for viewing and editing settings.json entries live.
/statusShows 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

Before you continue

  • settings.json controls model, permissions, env vars, proxy, and hooks.
  • Precedence: Managed → Local → Project → User — higher scopes win.
  • Commit shared project settings; keep secrets in settings.local.json.
  • Use /config and /status to inspect the merged configuration.
  • Next lesson: Permission Modes — controlling what Claude Code can read, write, and execute.

What's Next

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