Safeguard
Supply Chain•

How should a Node golden path configure npm scopes and registries?

Map your internal scope to your private registry in a committed .npmrc so internal names cannot be resolved from the public registry by mistake.

Safeguard Security Team
4 min read

In a Node template, commit a project .npmrc that maps your organization's scope to your private registry, and publish every internal package under that scope. That way an internal name is never looked up on the public registry by accident.

What scopes do

npm's documentation says a scope allows you to create a package with the same name as a package created by another user or organization without conflict. The scope is the part between the @ and the slash, as in @yourorg/package-name. It also states that unscoped packages are always public, and private packages are always scoped.

That second fact is the useful one for a platform team. If an internal package has an unscoped name, someone can publish a public package with the same name, and a misconfigured install may pick it up. This class of problem is usually called dependency confusion. See dependency confusion and private registries for the background.

What to put in the template

ItemWhy
Project level .npmrcApplies to everyone who clones the repo, including CI
Scope to registry mappingRoutes @yourorg packages to the private registry
No credentials in the fileTokens come from CI secrets or the developer's own user config
Lockfile committedRecords exactly which registry and version resolved
npm ci in CIStrict install, fails on drift

npm reads configuration from several .npmrc locations, including per project and per user files. Check the npmrc documentation for the order of precedence before you rely on one file overriding another.

Steps

  1. Choose one scope for all internal packages and reserve the same name on the public registry if you can, so nobody else can claim it.
  2. Rename any internal unscoped packages. Publish the old names as deprecated pointers during transition if consumers need time.
  3. Add the scope mapping to the template .npmrc.
  4. Configure CI to authenticate with a short lived or narrowly scoped token.
  5. Add a check that fails the build if a dependency in package.json is unscoped but present in your internal package list.
  6. Test from a clean machine: a fresh clone should install without any personal configuration.

Mistakes to avoid

  • Committing a token in .npmrc. Use environment variable references or CI secrets.
  • Pointing the default registry at a private proxy without deciding what it does for packages it does not hold. Know whether it falls through to the public registry.
  • Leaving old unscoped internal names in older services.
  • Assuming a lockfile alone fixes this. It records what was resolved, but the first resolution still needs to be correct.

Verify with a clean install

The most useful test is a new developer laptop or a clean container. If install works only because of local configuration, the template has a gap that will bite the next team.

Where Safeguard fits

Safeguard scans your resolved dependencies, applies policies and gates to changes, and monitors components over time, so unexpected packages show up in the inventory. Try a free scan at gold.safeguard.sh/scan.

Try it yourself

Open the inventory and look for packages whose source or name you do not recognize, which is the signal a scope mistake leaves behind.

Click through it at your own pace, or open it full screen.

Quick check

Are unscoped packages ever private?

Per npm's documentation, unscoped packages are always public and private packages are always scoped.

Can the template .npmrc hold the auth token?

It should not. Keep credentials in CI secrets or user level configuration.

Sources

Last reviewed: 19 October 2026.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.