CoreMesh

Where Is Claude Code settings.json? Locations and Examples

Where Claude Code settings.json files live, which one wins, how permissions allow/deny rules work, and example configs you can paste into your project.

Claude Code reads settings from JSON files at several levels: managed, user (~/.claude/settings.json), shared project (.claude/settings.json) and project local (.claude/settings.local.json). Installing Claude Code doesn't create any of them, so you create the one you need, or let Claude Code write it the first time you change an option in /config or approve a permission.

For permissions, add allow, ask and deny rules under a permissions key. For environment variables, use an env key. If a value seems ignored, run /status to see which files were loaded.

Claude Code settings.json file locations#

Scope File Who it affects
Managed Deployed by your organization You don't create or edit it
User ~/.claude/settings.json You, in every project
Shared project .claude/settings.json Everyone who clones the repo
Project local .claude/settings.local.json You, in this project only

On Windows, ~/.claude means %USERPROFILE%\.claude. To keep the home-directory files somewhere else, set CLAUDE_CONFIG_DIR. Claude Code then stores settings, session history and plugins there.

There's also a fifth file, ~/.claude.json. Claude Code writes it for itself. It holds your sign-in session, MCP server configurations, per-project trust decisions and the global config keys that /config writes. You don't need to edit it, and it isn't the same thing as settings.json.

When Claude Code creates the files for you#

  • ~/.claude/settings.json appears the first time you change a /config option stored in user settings, such as the theme.
  • .claude/settings.local.json appears the first time you choose a standing approval such as "Yes, and don't ask again" for a Bash command. A few /config options, including Show tips, save there too.
  • The shared .claude/settings.json you create yourself in the project folder.

Which file wins: precedence in practice#

The local file applies over the committed one. Say your team's .claude/settings.json sets the model to Sonnet and you prefer Opus. Put this in .claude/settings.local.json and only your sessions change:

json
{
  "model": "claude-opus-5-5"
}

A --settings flag or a managed source can also sit above your file. /status shows what loaded, and the official settings page has the full stack.

A few details matter in git repositories:

  • Started in a subdirectory, Claude Code reads and writes the local file at the repository root. In a worktree it uses the main checkout's root.
  • It reads the shared .claude/settings.json from the session's primary working directory, so start Claude Code at the repository root to use a file committed there.
  • The file stays beside .claude/settings.json instead when you're outside a git repository, when the root is your home directory, on Windows, or when the root, .git or .claude isn't owned by your user.

When Claude Code first writes the local file, it adds **/.claude/settings.local.json to your global git excludes file. If you created the file by hand and Claude Code hasn't written to it yet, add it to .gitignore yourself.

Permissions allow and deny rules#

Rules use the format Tool or Tool(specifier). Parentheses inside the specifier are literal, so you don't escape them.

The smallest useful config blocks Claude's file tools from reading secrets:

json
{
  "permissions": {
    "deny": [
      "Read(./.env)",
      "Read(./secrets/**)"
    ]
  }
}

A Read deny rule also blocks the Edit and Write tools on the same path, including creating a new file there. Edit rules apply to all built-in tools that edit files, so use Edit(docs/**) instead of Write(docs/**). Path rules written for Write, NotebookEdit, Glob or MultiEdit are accepted but never consulted.

Path pattern prefixes#

Read and Edit rules use gitignore pattern syntax:

Pattern Meaning Example
//path Absolute path from filesystem root Read(//Users/alice/secrets/**)
~/path Path from home directory Read(~/Documents/*.pdf)
/path Relative to the settings source Edit(/src/**/*.ts)
path or ./path Relative to current directory Read(*.env)

A single leading slash is not an absolute path. In project settings, /path resolves to <primary working directory>/path; in user settings it resolves to ~/.claude/path. So Read(/secrets/**) in user settings blocks ~/.claude/secrets/**, not a secrets folder in your project. For a user-level rule that applies everywhere, use // or ~/.

Depth matters for single-segment directories#

Edit(src/**) as an allow rule matches only <cwd>/src. As a deny or ask rule it matches a src directory at any depth. Use Edit(**/src/**) if you want any depth in every rule type.

Carving out exceptions#

A deny or ask pattern starting with ! is a gitignore negation. In the same file's deny list:

json
{
  "permissions": {
    "deny": ["Read(*.env)", "Read(!sample.env)"]
  }
}

This blocks every file ending in .env except sample.env. Put the ! rule after the rule it carves from. It only affects rules from the same source, and it can't reopen a file inside a directory that another rule blocks as a whole.

Example configs#

A personal user-level file with a deny list that uses home-relative and absolute paths:

json
{
  "permissions": {
    "deny": [
      "Read(~/.ssh/**)",
      "Read(//**/.env)"
    ]
  }
}

The //**/.env rule blocks any .env anywhere on the filesystem. A plain Read(.env) only covers the current directory and below.

You can sanity-check a rule list for the common slip of using a single leading slash in user settings. This script only reads an inline string and prints warnings:

javascript
const settings = JSON.parse(`{
  "permissions": {
    "deny": ["Read(/secrets/**)", "Read(./.env)", "Write(docs/**)", "Read(~/.ssh/**)"]
  }
}`);

for (const rule of settings.permissions.deny) {
  const m = rule.match(/^(\w+)\((.*)\)$/);
  if (!m) { console.log(rule, "-> tool-level rule"); continue; }
  const [, tool, spec] = m;
  if (!["Read", "Edit"].includes(tool)) {
    console.log(rule, "-> path rules for", tool, "are never consulted; use Edit or Read");
  } else if (spec.startsWith("/") && !spec.startsWith("//")) {
    console.log(rule, "-> anchors at the settings source, not the filesystem root");
  } else {
    console.log(rule, "-> ok");
  }
}

Anthropic also publishes starter settings configurations for common deployment scenarios in the claude-code examples folder. Treat them as starting points.

Settings that don't apply from every file#

Some keys are ignored depending on where you put them:

  • permissions.defaultMode values auto and bypassPermissions don't take effect from project or local settings. Set them in user or managed settings, or pass --permission-mode for one session.
  • Telemetry export variables in an env block don't take effect from project or local settings, apart from a few off values.
  • permissions.allow rules, permissions.additionalDirectories, extraKnownMarketplaces and most env values in the shared file apply only after each teammate trusts the folder. deny and ask rules apply right away.
  • Keys marked User, Managed or Global config in the settings index never apply from the shared file. Global config keys apply only from ~/.claude.json.

Allow rules in your untracked local file apply without the trust step. If git tracks that file, the trust step applies to it too.

Common mistakes and "not working" fixes#

  1. Broken JSON. Invalid JSON or a rejected value makes Claude Code skip the file or the entry. Validate the file first.
  2. A higher level sets the same key. Another file, a --settings flag or a managed source may win. Check /status.
  3. Still prompted after "don't ask again". That saved an allow rule to your local file, and a local allow doesn't outrank an ask rule from a project or managed file.
  4. Change lost in new sessions. /model saves to ~/.claude/settings.json. If another tool generates that file or links it read-only, the change lasts only for the session.
  5. Wrong anchor. /Users/alice/file isn't absolute. Use //Users/alice/file.
  6. Expecting deny rules to stop everything. Read and Edit deny rules cover built-in file tools, recognized Bash file commands like cat and sed, and redirections. They don't cover a Python or Node script that opens files itself. For OS-level enforcement, enable the sandbox.
  7. .claudeignore. It has no effect. Move its entries into Read deny rules.
  8. Org rules. Claude Code merges permissions.allow across scopes, so your organization's allow rules still apply alongside yours unless it sets allowManagedPermissionRulesOnly.

Quick reference#

  • Create .claude/settings.json for team rules, .claude/settings.local.json for personal overrides, ~/.claude/settings.json for everything you do.
  • Put secrets under permissions.deny as Read(...) rules; I'd start there before anything else.
  • Use // or ~/ for paths outside the project.
  • Keep auto and bypassPermissions out of project files.
  • Run /status whenever a value seems ignored.
  • Details for every key live in the settings documentation and the permissions documentation.

Quick answers

Where is the Claude Code settings.json file?

The user file is ~/.claude/settings.json (%USERPROFILE%\.claude on Windows). Project files are .claude/settings.json and .claude/settings.local.json in the project folder. Claude Code doesn't create them at install.

Why is my Claude Code settings.json not working?

Usually a higher-priority file, a --settings flag or a managed source sets the same key, or the JSON is invalid so the file or entry is skipped. Run /status to see which files loaded.

Can I set the model in settings.json?

Yes, use the model key, for example "model": "claude-opus-5-5". Put it in .claude/settings.local.json to change it only for yourself in one project.

Is ~/.claude.json the same as settings.json?

No. ~/.claude.json is written by Claude Code for itself and holds your sign-in session, MCP server configurations, per-project trust decisions and global config keys. You don't need to edit it.

Did this solve it?

One tap. No account.

Saved you an hour? Send a tip.

USDC or ETH on Base. Keeps the notes free and the examples running.

Base
QR code with the CoreMesh tip address on Base
0x9dFD2Ee86182f92464b50809C6702B999a0Cd54f
Open in wallet · 5 USDC

On a computer? Scan the code with your phone wallet, or copy the address.

USDC or ETH on Base works best. Other tokens on Base, Ethereum or Arbitrum also reach this address. Tips are optional and unlock nothing; every guide stays free.

Discussion

Start the discussion

`code` and ``` blocks work

No account needed. Comments are read before they show up, usually the same day. Your email is never asked for.

Indra Wijaya

Builds and runs AI agents, bots and content pipelines, and writes down what works and what broke.

About · Email · RSS

Keep reading

New notes, no spam.

One post at a time, only when there's something worth reading. Follow in any feed reader.

Subscribe via RSS