Claude Code settings.json: Hierarchy, Precedence and env Setup

Blog / Developer tools

Claude Code settings.json: Hierarchy, Precedence and env Setup

Claude Code settings.json lives in four places: the user-level ~/.claude/settings.json, the project-shared .claude/settings.json, the project-local .claude/settings.local.json, and a managed policy file pushed down by an administrator. When the same field appears in more than one place, the one closer to "this machine, this project" wins, and managed policy wins over everything. Variables such as the API endpoint and proxy go in the env field. After you write them, check the effective values with /status instead of guessing.

The sections below follow this order: where the files are, who overrides whom, what to put in them, and how to verify. Field names and paths follow the official Anthropic settings docs. Claude Code updates often, so if anything here differs from the docs, trust the current version of the docs.

How many settings.json files are there, and where do they go?

LevelPathWho it applies toCommitted to the repo?
Managed policymacOS: /Library/Application Support/ClaudeCode/managed-settings.json; Linux / WSL: /etc/claude-code/managed-settings.json; Windows: see the official docsPushed out centrally by company IT or an administratorNot in the repo
User~/.claude/settings.jsonYou, in all projectsNo
Project shared<project>/.claude/settings.jsonEveryone on the teamYes
Project local<project>/.claude/settings.local.jsonYou, in this project onlyNo

A few points that are easy to mix up:

  • ~/.claude.json (note: no subdirectory) is a state file that Claude Code maintains itself. It holds login state, project history, MCP servers and similar data. It is not a settings.json, and you generally don't need to edit it by hand.
  • CLAUDE.md is a project description for the model to read. It counts as "memory", not configuration. Don't put permissions or environment variables in CLAUDE.md; they won't be applied as settings.
  • When Claude Code creates settings.local.json, it configures git to ignore it automatically. If you created it by hand, check your .gitignore yourself.

When several files conflict, which one wins?

The official docs give this precedence, from highest to lowest:

  1. Managed policy (managed-settings.json)
  2. Command-line arguments (for example --model, --settings <file>, --permission-mode)
  3. Project local .claude/settings.local.json
  4. Project shared .claude/settings.json
  5. User ~/.claude/settings.json

This is the "five-layer precedence" people often mention. The order alone is easy to misread, so keep two more rules in mind.

Scalar fields are overridden by precedence. If model is set to one value at the user level and another in the project-local file, the project-local value takes effect. Variables with the same name inside env work the same way: the higher layer wins.

Permission rules are merged, not overridden. Arrays such as permissions.allow and permissions.deny are combined across layers when rules are evaluated, and deny takes priority over allow. So if your team denies Bash(curl:*) in the shared project config, allowing it locally does nothing. A deny in managed policy cannot be undone by the user at any layer.

Common fields at a glance

FieldWhat it doesExampleRecommended layer
envEnvironment variables set automatically for every session{"HTTPS_PROXY": "http://127.0.0.1:7890"}Depends on the variable; see the next section
permissions.allow / deny / askRules that allow, block, or require confirmation for tool calls"Bash(npm run test:*)", "Read(./.env)"Team conventions in project shared; personal habits in local
permissions.defaultModeDefault permission mode"acceptEdits"User or local
permissions.additionalDirectoriesPaths outside the working directory that Claude may access["../shared-lib"]Local
modelDefault modelA model alias or IDUser or local
apiKeyHelperGenerates the auth value with a script so the key is never written to a file"~/bin/get-key.sh"User
hooksRun commands before or after tool calls, for example auto-formattingSee the official hooks docsTeam standards in project shared
includeCoAuthoredByWhether git commits carry a Claude co-author linefalseProject shared
cleanupPeriodDaysHow many days to keep local session transcripts30User
statusLineCustomizes the status line at the bottomA command configUser

Before you start writing, you can add "$schema": "https://json.schemastore.org/claude-code-settings.json" as the first line of the file. Editors such as VS Code use it for field completion and validation, so a misspelled field name shows up immediately.

What does env do for the API endpoint and proxy, and how far does it reach?

env has the same effect as exporting those variables for you before Claude Code starts. It applies to the Claude Code process itself, and commands that Claude Code runs through the Bash tool can generally read them too. It does not change your system environment, and it does not affect programs you run by hand in another terminal.

The common variables fall into three groups, and each belongs in a different place:

CategoryVariablesWhere to put themWhy
API endpoint and authANTHROPIC_BASE_URL, ANTHROPIC_AUTH_TOKEN, ANTHROPIC_API_KEYUser level or settings.local.jsonThey contain secrets and must never go into the repo
Network proxyHTTPS_PROXY, HTTP_PROXY, NO_PROXYUser level or localEveryone's network is different
Behavior switchesDISABLE_TELEMETRY, CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC, API_TIMEOUT_MS, BASH_DEFAULT_TIMEOUT_MSTeam-wide ones can go in project sharedThey contain no personal information

A few things that tend to bite in practice:

Proxy variables are inherited by child commands. If you set HTTPS_PROXY in env, then npm install and git fetch run by Claude Code also go through that proxy. If an internal repository or a domestic mirror in China should not go through the proxy, list it in NO_PROXY, for example "NO_PROXY": "localhost,127.0.0.1,.internal.example.com".

If only one project needs a different endpoint, put it in the local file. Say you normally use the official endpoint, but one project has to go through a company gateway. Write ANTHROPIC_BASE_URL into that project's .claude/settings.local.json and other projects are unaffected. For how to fill in the endpoint, and where the equivalents for Codex and OpenCode go, see Configuring a custom API endpoint for Claude Code, Codex and OpenCode. It is not repeated here.

If the shell sets a variable with the same name, trust /status. Per the official docs, env in settings is applied to every session, but how a variable already present in your shell interacts with a same-named one in settings may differ between versions. When you hit "I changed it and nothing happened", the first step is the verification list below, not editing the file again and again.

Variables that must be read when the process starts belong in the shell. Something like NODE_EXTRA_CA_CERTS (for a company's self-signed certificate) is read by Node.js during startup, so putting it in the settings env may be too late. The safer approach is to export it in your shell config.

After a change, how do you confirm which layer took effect?

Work through these checks in order:

  1. Validate the JSON syntax. A single stray comma can cause the whole file to be ignored:
    for f in ~/.claude/settings.json .claude/settings.json .claude/settings.local.json; do
      [ -f "$f" ] && (python3 -m json.tool "$f" >/dev/null && echo "OK  $f" || echo "BAD $f")
    done
    
  2. Restart the session. Settings are read at startup, and a session that is already open may not reload env. Exit and run claude again.
  3. Run /status inside the session. It shows the current auth method, model, API endpoint and similar information, and some versions also list which settings sources were read. Check that the endpoint and proxy are the values you expect.
  4. Run /permissions to list the allow / deny rules currently in effect. If a rule seems to do nothing, see whether a deny from another layer is covering it.
  5. Run /config to open the settings UI, where you can view and change commonly used user-level options. Pay attention to which layer's file it modifies, and if you're unsure, go back to step 3 to cross-check.
  6. Ask Claude to print the environment variables. Have it run env | grep -iE 'proxy|anthropic' and look at the values the Bash tool sees. The output may contain secrets, so view it only on your own machine and don't paste it into a group chat or an issue.
  7. When something goes wrong, run /doctor. It checks the installation and configuration, and some versions flag invalid fields in settings files.

If /status shows everything is correct but requests still time out or fail, the problem is most likely not in the config files but in the network or on the server side. In that case work through Troubleshooting Claude Code connection timeouts and errors: a four-layer network checklist layer by layer. You can also open Is Claude Code down? and Anthropic API status to see whether the service currently has an outage, so you rule out their side before investigating yours. To check whether the proxy is actually in effect and where your exit IP is, use IP and environment check.

How do you split team-shared config from personal config?

A fairly safe split: the repo holds only what everyone should have identically, and anything tied to a person, a machine, or a secret stays local.

Project shared .claude/settings.json (committed to the repo), example:

{
  "$schema": "https://json.schemastore.org/claude-code-settings.json",
  "permissions": {
    "allow": [
      "Bash(npm run lint)",
      "Bash(npm run test:*)"
    ],
    "deny": [
      "Read(./.env)",
      "Read(./.env.*)",
      "Read(./secrets/**)"
    ]
  },
  "env": {
    "DISABLE_TELEMETRY": "1"
  },
  "includeCoAuthoredBy": false
}

Project local .claude/settings.local.json (not committed), example:

{
  "env": {
    "ANTHROPIC_BASE_URL": "https://api.example.com",
    "ANTHROPIC_AUTH_TOKEN": "replace with your own key",
    "HTTPS_PROXY": "http://127.0.0.1:7890",
    "NO_PROXY": "localhost,127.0.0.1"
  },
  "permissions": {
    "additionalDirectories": ["../my-scratch"]
  }
}

The addresses, ports and directories above are examples. Replace them with your own values.

Add this to .gitignore:

# Claude Code personal config, keep out of the repo
.claude/settings.local.json
# If anyone likes to keep a CLAUDE.local.md in the project, ignore that too
CLAUDE.local.md

Before committing, double-check once more:

git check-ignore -v .claude/settings.local.json   # should print the matching ignore rule
git ls-files .claude/                              # settings.local.json should not appear

If a key has already been committed, adding it to .gitignore is not enough. You need to revoke that key in the provider's console and create a new one. Before handing your code and config to a third-party endpoint, read its data policy first; see Can your code and conversations be seen when you use a third-party AI API?

Frequently asked questions

I changed settings.json and nothing happened?

Check in this order: is the JSON valid, did you restart the session, does a higher layer override the same field, does the shell set a variable with the same name, and what value does /status show. Most cases are settled in the first three steps.

Can I switch to a different config for just one launch?

Yes. Use claude --settings ./some-file.json to load an extra settings file. Its precedence sits at the command-line-argument level, above project and user config, which makes it handy for temporarily testing another endpoint or model without touching your usual files.

The config is right, but it's slow?

Then it's not a config problem. Latency usually comes from the network path, the proxy node, or server-side queuing; see Claude Code responses are slow: where latency comes from and how to diagnose and reduce it. For which domains and ports to allow, see Network requirements for Claude Code and Codex. In a browser you can also use the cdnping online speed test to look at first-connection and round-trip times to each vendor's API, as a reference.

One last reminder: when you use Claude Code through a proxy or a third-party endpoint, follow Anthropic's terms of service and the laws where you are. Regional availability is as stated by the official documentation.

Related articles

Keep reading