npm merges settings from command line flags, environment variables and four npmrc files: project, user, global and built-in. Higher sources override lower ones. Auth tokens must be scoped to a registry host in the key name, and the safest place for the value is an environment variable referenced from the file.
The sources, in priority order
The npm docs list the sources by priority. In the config source, the precedence for conflicts is: command line, environment, project, user, global. The built-in file sits at the bottom and is mostly for people who package npm itself.
| Source | Location | Notes |
|---|---|---|
| Command line | flags | Highest priority |
| Environment | variables beginning with npm_config_ | Underscores replace dashes |
| Project | .npmrc next to package.json | Only applies to the project root |
| User | .npmrc in the home folder | Per person |
| Global | etc/npmrc under the prefix | Per machine |
| Built-in | npmrc inside npm | Unchangeable by users |
Two details from the docs: a project .npmrc has no effect when your package is published, so a module cannot force settings on consumers, and it is not read in global mode such as installing with the global flag.
Why tokens are scoped to a host
The auth keys, including _authToken and _auth, must be scoped to a registry. The docs state this ensures npm will never send credentials to the wrong host. The prefix is a URI fragment:
; good
@myorg:registry=https://registry.example.org/myorg
//registry.npmjs.org/:_authToken=${NPM_TOKEN}
; bad, unscoped
_authToken=MYTOKEN
A scope can cover a whole host or a path on that host, so two scopes on one host can use different tokens.
Keep the secret out of the file
The docs say environment variables can be substituted with ${VARIABLE_NAME} in npmrc files. If the variable is not defined, the text is left unreplaced, and adding a question mark after the name makes it evaluate to an empty string. Use that so the committed project file contains a reference, not a token. Put the real value in your CI secret store.
Habits that follow:
- Commit a project .npmrc with registries and scopes, never with a literal token.
- Keep personal tokens in the user file, outside any repository.
- Use the narrowest token that works, and rotate it. See rotating a CI registry token.
- Check that .npmrc is not copied into container images or build contexts.
Surprising precedence cases
A flag beats the project file, so a pipeline step with a registry flag overrides your committed policy. A user-level setting can also differ from CI, which is a common reason an install works on a laptop and fails in a pipeline. When debugging, run npm config list to see which source supplied each value.
Unknown keys
Starting in npm v11.2.0, npm warns when it finds unsupported keys in .npmrc, and a future major version may stop accepting them. For tool-specific settings the docs recommend environment variables or the config field in package.json.
Where Safeguard fits
Config controls what npm does. Safeguard's dependency scanning and policies check what your lockfiles resolve afterward, which is useful when a precedence surprise sends an install to the wrong place. A free scan is at https://gold.safeguard.sh/scan.
Quick check
Does a project .npmrc apply to people who install my package?
No. The docs say it has no effect when your module is published, so you cannot force settings on consumers.
Why must tokens be scoped to a registry?
So npm never sends credentials to the wrong host. Unscoped keys are treated as bad config in the npm docs.
Sources
Last reviewed: 19 October 2026.