Changing package managers doesn't remove your npm registry dependency

By

Tagged: Node.js

npm is both a command and a package registry. Learn what switching to pnpm or Bun changes, and how caches, lockfiles, and mirrors affect failed installs.

You can replace npm install with another command and still download your packages from the same server.

That gets lost whenever an install fails and someone recommends switching package managers. Sometimes that fixes it, and sometimes the new command makes the same request to the same server and fails too.

npm means two things

The npm CLI is the program you run in your terminal. It reads the project, resolves dependencies, and installs packages.

The npm registry is a service that stores package metadata and package archives, at registry.npmjs.org. The CLI’s registry documentation explains how the client chooses one.

pnpm, Yarn and Bun all talk to that same service by default. They lay out node_modules differently on your disk, and download from the same place.

Fig 1 · 1/4Which part of the install changed?
npm fetches from the public registry

Replacing the client changes the first box in the figure. A warm cache can answer a request locally, and only a separate registry or proxy changes the network path.

Find which part failed

When a deploy stops while installing dependencies, read the first useful error before replacing npm with pnpm.

A package archive returning a 5xx error is a different problem from an unsupported Node version. An install script can fail after the archive downloaded fine, and authentication can fail for a private package while public ones still install.

Write down the package name and the URL in the error, if there is one, and compare the Node and package-manager versions between the working and failing environments. Then check whether the failure happens before or after package scripts start.

For an npm project, this command prints the configured default registry:

npm config get registry

Then look at where each client gets its registry. A scope such as @flaviocopes can use a different registry from the default. Be careful when you share these files, because auth tokens often sit next to the registry lines.

Where each client reads the registry

npm reads .npmrc, from the project root, then ~/.npmrc, then the global config. The npmrc documentation shows the format. This sets the default registry and sends one scope to GitHub Packages:

registry=https://registry.npmjs.org/
@flaviocopes:registry=https://npm.pkg.github.com/
//npm.pkg.github.com/:_authToken=${NPM_TOKEN}

The token line is tied to a registry URL, so npm only sends it to that host. registry.npmjs.org is already the default, so you only need that first line if something else changed it.

pnpm reads the same .npmrc lines. Its settings page says only auth, registry, TLS, proxy and local-address settings are read from .npmrc, and everything else goes in pnpm-workspace.yaml. You can also declare registries there:

registries:
  default: https://registry.npmjs.org/
  "@flaviocopes": https://npm.pkg.github.com/

Bun reads .npmrc too, including registry and @scope:registry, so the npm file above works unchanged. Its own config file is bunfig.toml, which the bunfig docs configure like this:

[install]
registry = "https://registry.npmjs.org"

[install.scopes]
flaviocopes = { token = "$NPM_TOKEN", url = "https://npm.pkg.github.com/" }

Yarn Berry (Yarn 2 and later) ignores .npmrc. It reads .yarnrc.yml, with npmRegistryServer for the default and npmScopes for scopes, written without the @:

npmRegistryServer: "https://registry.npmjs.org"

npmScopes:
  flaviocopes:
    npmRegistryServer: "https://npm.pkg.github.com"

Yarn’s default is https://registry.yarnpkg.com, which serves the same packages as the npm registry.

So switching from npm to pnpm or Bun keeps your registry, because they read the same file. Switching to Yarn Berry without porting the scope lines sends your private packages to the public registry, where the install usually fails with a 404.

Find the failed part of an installInstallation failures can come from downloading packages or from local execution. Inspect the first error before deciding whether to replace the client.Package downloadInstall scriptInstall failsWhere did it fail?Check URL, registryand authenticationInspect script andruntime errorChoose a fix forthat cause

Keep the lockfile

A lockfile records the dependency tree you agreed to install. Deleting it during an outage adds another variable: the next install can resolve different dependency versions.

For automated npm installs, use npm ci. It requires a lockfile and fails when it disagrees with package.json, instead of quietly updating it. It also removes an existing node_modules before installing.

npm ci

A committed lockfile makes the install repeatable, but the package archives still have to come from somewhere, so a fresh build machine needs the registry even when every version is pinned.

The package-lock.json documentation describes the resolved locations and integrity information recorded for packages.

A cache only helps with packages it has

A local cache saves downloads and speeds up repeated builds. A build that works from a warm cache tells you the app still builds, and nothing about whether a clean machine can fetch every dependency.

npm describes its cache as self-healing, and explicitly advises against treating it as a reliable permanent package store.

During a registry outage, don’t clear a working cache as a reflex, because you can delete the very files that let the machine keep building.

In a deployment pipeline, a package-download cache and an old node_modules directory are different things. Key the cache on the environment and the lockfile, since restoring dependencies built for another platform creates a new failure that has nothing to do with the registry.

When a proxy helps

A caching registry proxy keeps copies of packages your team already fetched. Your clients request packages through it, by pointing the registry lines above at the proxy, and it retrieves missing ones upstream.

During an outage it only helps with what it has stored, so a new dependency can still need the public registry. You also take on running the proxy, controlling access, and keeping its data.

Before adopting one, start a clean build with upstream access disabled and see whether it completes with only the packages the proxy holds.

For a small project, a committed lockfile and a sensible CI cache are usually enough. If your releases depend on installing packages at any moment, run that clean-runner test before you need it.

Want me to talk about your product? You can sponsor this site.

Related posts about node: