Skip to main content
Claude Code tips · Lesson 11 of 13 · 10 min

Claude Code Settings Scopes: Which File Wins, What Is Shared

Claude Code settings scopes explained from a real repo: user, project, local and managed files, which one wins, what git shares, and how lists merge.

By Matthews WongReviewed on Checked against Claude Code v2.1.301

Key takeaway

Claude Code reads settings from a user file, a shared project file, a local project file, and managed policy from an organization. When two of them set the same key, the higher level wins, but list keys such as permissions.allow are combined. Only the shared project file is meant for git, so the scope you pick decides who gets the setting.

You will be able to

  • Pick the scope a setting belongs in: just you, just this project, or the whole team.
  • Predict which value Claude Code uses when two files set the same key.
  • Check which settings files actually loaded, and keep personal ones out of git.
Watch it work

Step through the diagram

Press Play, or step with the arrows. Every step is written out below the diagram.

One key, four places it can be set

A key set in the user file reaches the session unless the project, local or managed level sets it again; each higher level overrides the one below it, while list keys are combined instead.

Reviewed on 17 October 2026 · Claude Code v2.1.301

Step 1 of 6. Settings come from up to four sources, drawn here lowest to highest. When one key appears in more than one, the highest source supplies the value.

Keys: ← → step · Home / End · K play or pause

  1. Settings come from up to four sources, drawn here lowest to highest. When one key appears in more than one, the highest source supplies the value.

  2. Your user file sets a key for every project. Nothing above it sets the key, so its value reaches the session unchanged.

    // ~/.claude/settings.json "model": "A"
  3. The team commits the same key in the shared project file. It sits above your user file, so the team value replaces yours here.

    // .claude/settings.json (committed) "model": "B"Predict the next step You add the same key, with value C, to your local project file. Which value does your session use? (B, the committed team value · C, your local value · Both, merged together)
  4. The local file wins over the committed one, but only for you. Claude Code keeps it out of git, so teammates keep value B.

    // .claude/settings.local.json (not in git) "model": "C"
  5. If your organization sets a key in managed settings, that value wins over all three files. Nothing in your own files overrides it.

    Predict the next step The user and project files each list permissions.allow rules. What does Claude Code do with the two lists? (Uses only the project list · Combines both lists · Uses only the user list)
  6. List keys such as permissions.allow are combined across files, not overridden. Each file adds rules without removing another file's rules.

    permissions.allow // every file contributes entries

Which Claude Code settings scope should a setting live in?

Claude Code reads settings from four files, and an organization can also deliver managed settings from the claude.ai console. Each source has a scope, meaning the people and projects a setting applies to. The user file, ~/.claude/settings.json, is yours in every project on the machine. The shared project file, .claude/settings.json, applies to everyone who works in the folder, and in a git repository you commit it so teammates get it.

Read more (2)

The local project file, .claude/settings.local.json, is yours in this one project only. Claude Code keeps it out of git when it creates the file: the first time it writes the file, it adds a line for it to your global git excludes. If you create the file by hand, add it to .gitignore yourself. Managed settings come last: security policy and compliance rules that your organization deploys, and that your own files cannot loosen.

So the question to ask is who should get the setting. A hook or a permission rule the whole team needs goes in the shared file. A personal preference, or something you are still testing before you share it, goes in the local file or the user file. This repo follows that split: its committed .claude/settings.json holds exactly one thing every contributor needs, the figure-review hook, and nothing personal.

Which value wins when two settings files set the same key?

Claude Code uses the value from the highest level that sets the key. In order, highest first: managed settings, then JSON passed with the --settings flag for one session, then the local project file, then the shared project file, then the user file. A key you leave out at a higher level keeps its value from the levels below, so each file only needs the keys it changes.

Read more (2)

List keys are the exception. When permissions.allow appears in more than one file, Claude Code combines the lists, so each file can add entries without removing another file's. A few keys that hold model lists follow their own rules, and for a few security-sensitive keys Claude Code honors a stricter value from a lower level even over a managed one. Environment variables are not a level in this stack at all; for each pair of variable and key, the docs say which one applies.

Hooks behave like lists too. Hooks from every source are merged: all registered hooks fire for their matching events, whichever file defined them. That is why a personal hook in your user file runs beside the team's committed one rather than replacing it.

How do you check which Claude Code settings files loaded?

Run /status inside Claude Code. The Status tab has a Setting sources line that lists each settings file loaded for the session, such as User settings or Project local settings. It confirms which files were read; it does not show which file supplied each key. For entries Claude Code rejected, run claude doctor.

Read more (1)

To test one layer in isolation, start with the --setting-sources flag, which takes a comma-separated list of user, project and local, as claude --help shows. Settings files are strict JSON: a comment or a trailing comma is a syntax error, reported as a Settings Error at the next start.

How this site does it

The real config behind this lesson

Excerpts from the repository that builds and deploys this website, quoted as they are.

.claude/settings.json:1-17
{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Write|Edit",
        "hooks": [
          {
            "type": "command",
            "command": "node \"${CLAUDE_PROJECT_DIR:-.}/scripts/review-blog-figures.mjs\" --hook 2>/dev/null || true",
            "timeout": 30,
            "statusMessage": "Checking whether the figures fit"
          }
        ]
      }
    ]
  }
}

The shared project scope, in full. It is committed, so every contributor gets the same hook. The reason it can be this small is that nothing personal lives here: approvals you grant at a prompt are saved to .claude/settings.local.json, which stays out of git, and your own preferences stay in the user file.

What breaks

Mistakes that cost real time

  • A hand-made local file gets committed

    Claude Code adds .claude/settings.local.json to your global git excludes only the first time it writes the file. If you create the file yourself, nothing ignores it yet. This repo's own .gitignore does not list it either, so the protection is a per-machine setting. Check with git check-ignore -v before the first commit.

  • Expecting your file to beat managed settings

    Nothing in your own files or the --settings flag overrides a managed key. If a setting will not change, run /status and look at the Setting sources line for a managed source, then ask whoever administers it. A few restrictive keys are the reverse: a stricter value from any scope is honored.

  • Removing a rule from one file does not remove it

    Because permissions.allow is merged across files, an allow rule you delete from the shared file stays active if the user or local file also lists it. Open each file that could define it. Claude Code also merges your organization's allow rules with yours unless the organization restricts that.

  • A key in the wrong file is ignored

    Some keys never apply from the shared project file, only from user, local or managed settings, apart from a few a repository file can still switch off. If Claude Code ignores a key you committed, look at that key's scope in the settings reference. And some keys are read once at session start, so edit, then restart.

The four settings sources, lowest precedence first
User~/.claude/settings.jsonYou, in every projectNo
Shared project.claude/settings.jsonEveryone in the projectYes, commit it
Project local.claude/settings.local.jsonYou, in this projectNo, keep it out
Managedmanaged-settings.json, MDM or the consoleEveryone your organization deploys it toNot a repo file
Try it yourself

Do it on your own machine

You need Claude Code and a scratch git repository. You will set a rule in two scopes, confirm both loaded, and see a broken file reported.

  1. Create the shared file, .claude/settings.json, with one allow rule. Commit it: this is the scope your team would get.

    mkdir -p .claude
    echo '{ "permissions": { "allow": ["Bash(git status)"] } }' > .claude/settings.json
    git add .claude/settings.json && git commit -m "Share a project setting"
  2. Create the local file by hand with a different allow rule, then ask git whether it is ignored. If the command prints nothing, add the file to .gitignore yourself.

    echo '{ "permissions": { "allow": ["Bash(git diff)"] } }' > .claude/settings.local.json
    git check-ignore -v .claude/settings.local.json
    # no output? then:
    echo ".claude/settings.local.json" >> .gitignore
  3. Start Claude Code and run /status. On the Status tab, find the Setting sources line: it should name the project settings and the project local settings.

    claude
    > /status
  4. Restart with only some sources and run /status again. The local file should drop off the Setting sources line.

    claude --setting-sources user,project
    > /status
  5. Break the local file on purpose with a trailing comma, restart, and read the Settings Error. Then run claude doctor for the details. Fix the file when you are done.

    echo '{ "permissions": { "allow": ["Bash(git diff)",] } }' > .claude/settings.local.json
    claude
    # then, from a shell
    claude doctor
Quick quiz

Three questions before you move on

Pick an answer to see why it is right or wrong. Nothing is saved or graded, so guess freely.

  1. 1.The team commits a model choice in .claude/settings.json, and you want a different one only for your own sessions. Where do you set it?
  2. 2.The project file lists one permissions.allow rule and your user file lists a different one. Which rules apply in that project?
  3. 3.Your local settings file sets a key that your organization also sets in managed settings. Which value does Claude Code use?
Think it through

Answer in your head, then check

  1. 1.What does the Setting sources line in /status tell you, and what does it not?Show the answer

    Answer:It lists each settings file Claude Code loaded for the session, so you can confirm a file was read. It does not say which file supplied each key. For rejected entries, run claude doctor.

  2. 2.Why does a hand-made settings.local.json need its own .gitignore line?Show the answer

    Answer:Claude Code only adds the file to your global git excludes the first time it writes the file itself. A file you created by hand has no such protection yet, and a committed local file would share your personal settings.

  3. 3.A teammate's personal hook and the committed team hook both match the same event. Does one replace the other?Show the answer

    Answer:No. Hooks merge: all registered hooks fire for their matching events, whichever source defined them.

Go deeper

Related deep dives on this site