npm ERR! network: How to Fix npm Install Timeouts with a Registry Mirror
Symptom: npm install hangs or fails with network errors
The classic trio on constrained networks:
npm ERR! network request to https://registry.npmjs.org/xxx failed
npm ERR! network This is a problem related to network connectivity.
npm ERR! network ETIMEDOUT / ECONNRESET / ERR_SOCKET_CONNECTION_TIMEOUT
npm defaults to the official registry (registry.npmjs.org, a CDN outside many regions) which can be slow or unreachable. Work through the fixes in order — most cases resolve at step one.
Step one: switch to a fast registry mirror
# Check current registry
npm config get registry
# Switch to npmmirror (the China mirror, formerly taobao)
npm config set registry https://registry.npmmirror.com
# Verify
npm config get registry
# https://registry.npmmirror.com
npmmirror syncs with the official registry at minute-level frequency — more than enough for daily development. Re-run npm install to verify.
One-off use (without changing global config, e.g. when publishing):
npm install --registry=https://registry.npmmirror.com
Step two: clean the cache (if the error persists after switching)
npm's local cache may hold failed responses:
npm cache clean --force
npm cache verify
npm install
Step three: hunt stale proxy configs
If a proxy was configured before (by you, a colleague, or a tool) and the proxy is now dead, npm keeps sending requests to it — symptoms identical to a direct-connection timeout:
npm config list # look for proxy / https-proxy / odd registry
npm config delete proxy
npm config delete https-proxy
# Env vars affect npm too (HTTP_PROXY / HTTPS_PROXY / NO_PROXY)
env | grep -i proxy
Classic trap: you configured a proxy at the office and forgot to remove it at home; or a system-level proxy (set by a proxy client or VPN) that npm does not automatically pick up — npm only reads its own config and env vars, so make sure the tool is in global-takeover mode, or point npm explicitly at the local proxy port.
Step four: the package-lock trap
package-lock.json records the registry URL used at install time (the resolved fields). If the lock file was generated on another machine with a different registry, those resolved URLs may point somewhere you can't reach:
# Inspect where resolved points
grep -m3 '"resolved"' package-lock.json
# If it points to a broken source: delete the lock and reinstall
# (note: dependency versions may bump; teams must re-commit the lock)
rm package-lock.json node_modules -rf
npm install
Team note: lock files belong in git; the registry decision should be team-wide (or committed as a project .npmrc — see below).
Long term: project-level .npmrc
Put a .npmrc in the repo root and commit it — teammates get the same registry on clone:
registry=https://registry.npmmirror.com
One caveat: if the team publishes packages to npm, publishing needs a one-off --registry=https://registry.npmjs.org (npmmirror is a read-only mirror).
The mirror decision tree (China and beyond)
Symptoms first: is it timeouts (network path — mirror solves), TLS errors (corporate MITM proxy — registry config alone will not fix the CA), or 403/rate-limits (auth or registry policy — token config, not mirror)? Mirrors solve the first: a domestic registry mirror (npmmirror for China) cuts package fetch latency from seconds-over-GFW to milliseconds. The configuration cascade: project .npmrc (committed — the whole team gets it, CI included) beats user ~/.npmrc (one machine) beats environment variables (ephemeral). The nuance most teams miss: set both registry= and, for publish, an explicit @myscope:registry= back to the official — mirrors are read-only, and a publish against a mirror fails confusingly without it.
Lockfile integrity under mirrors
The reassuring fact: registry choice does not change package identity — tarballs are content-addressed by integrity hashes in package-lock.json, and a mirror serving different bytes fails the integrity check loudly. What does differ: metadata freshness (a mirror lagging hours behind can miss a just-published version — "version not found" that resolves itself later) and resolved URLs (lockfiles pin the mirror's URL scheme — switching mirrors later rewrites every resolved field; the diff is noise but harmless). The practice that avoids both: treat mirror config as infrastructure (uniform via .npmrc), and when a version genuinely is not found, check the canonical registry before assuming the package is broken.
Beyond npm: the pattern generalizes
Every package ecosystem has the same mirror architecture: pip (Tsinghua/Aliyun indexes via -i or pip.conf), Maven (settings.xml mirrors), Alpine apk, Homebrew bottles, Docker registries (registry mirrors — the same pull-latency economics), Go modules (GOPROXY chain with fallback), Rust crates (sparse index mirrors). The shared design lesson from each: mirrors accelerate reads, never own writes (publish always goes to canonical), integrity verification travels with the client (lockfiles, checksums — trust comes from content addressing, not from the mirror being friendly), and fallback chains (Go's GOPROXY=a,b,direct pattern) prevent a mirror outage from becoming a build outage. Configuring one ecosystem? The same three questions — reads, writes, verification — configure them all.
CI and container images: set the registry once
Local .npmrc does not magically travel into GitHub Actions or a Dockerfile unless you copy it. Patterns that hold up:
- Project
.npmrccommitted withregistry=pointing at the mirror your region trusts — every clone and every CI job inherits it - Build-arg / env override for teams that must publish from a different network than they install on (
npm_config_registryat install time, canonical registry only fornpm publish) - Docker layer cache — if
RUN npm ciprecedesCOPY .npmrc, the install still hits the default registry; copy config before install
When a pipeline is “fast on a laptop, slow in CI,” compare which registry each environment resolves — npm config get registry inside the job is the one-line truth.
Diagnosing “network” that is not the registry
Not every npm ERR! network is registry latency:
| Symptom | Often actually | Next check |
|---|---|---|
| Hang then timeout on one package | Binary postinstall (Chromium, sharp) | Package-specific download env vars |
| Fail only behind corporate proxy | Stale proxy / https-proxy in user npmrc | npm config delete proxy and retest |
| Integrity mismatch after mirror switch | Corrupt cache, not the mirror bytes | npm cache clean --force then reinstall |
| ECONNRESET mid-tarball | Unstable link / MTU issues | Retry; smaller concurrent sockets (npm config set maxsockets 3) |
Treat the registry mirror as the first lever for registry.npmjs.org timeouts — not as a universal solvent for every download path npm triggers.
FAQ
yarn / pnpm are also slow — same fix?
Yes, each has its own config system:
yarn config set registry https://registry.npmmirror.com
pnpm config set registry https://registry.npmmirror.com
pnpm also reads a project .npmrc (shared with npm).
Some packages still download from the official registry?
Some packages resolve to GitHub Releases or bundled downloaders (puppeteer's Chromium, sharp's prebuilt binaries) — those bypass the registry entirely. Targeted fixes: set the package's own mirror env var (e.g. PUPPETEER_DOWNLOAD_BASE_URL) or skip the download (PUPPETEER_SKIP_DOWNLOAD=true).
Does the mirror ever miss packages or versions?
No. npmmirror is a syncing mirror of the official registry (minute-level sync) with full version fidelity. Only brand-new publishes have minutes of lag.
npm's problem or my network's?
curl -I https://registry.npmmirror.com # 200 = mirror reachable
curl -I https://registry.npmjs.org # is the official registry reachable
Mirror reachable but official not → switching solves it. Both unreachable → check local network, DNS, or firewall.
Triage notes
The four steps are ordered, with step one labeled as solving 90% of cases, because most failures are simply the official registry being slow or timing out over a direct link — switch the source and you are done; the later steps (cleaning the cache, stale proxy configs, the lockfile resolved trap) have ever more similar symptoms but are ever rarer. The proxy entry deliberately points out that its symptoms are identical to a direct-connection timeout — a proxy left stale after a network change is something no mirror switch can cure. The lockfile-integrity section can call mirror switching harmless because package identity is content-addressed by the integrity hash in the lock: a mirror serving different bytes fails verification loudly.
Provided by ToolVault. Related tools: Linux Cheatsheet, Dockerfile Generator, Run to Compose, HTTP Status Codes. See the homepage for more developer tools.
Related Tools
Related Articles
Linux Crontab in Practice: Commands, Logs, and Debugging
Crontab beyond syntax: three must-know commands, /etc/cron.d vs user crontabs, five-step debugging, PATH/timezone/% escaping, MAILTO, and what to do when you need second-level scheduling.
docker run to docker-compose: The Complete Migration Guide (with Flag Map)
Migrate docker run commands to docker-compose.yml: five advantages of compose over raw run, a flag-by-flag mapping table (ports, volumes, env, restart, networks), the classic pitfalls (bare -e passthrough, anonymous volumes, --rm semantics), and an online converter that runs locally in your browser.
Permission denied (publickey): 6 Reasons Git Push Fails Over SSH (and the Fix for Each)
git clone or push rejected with Permission denied (publickey) fatal: Could not read from remote repository? Covers missing keygen, key not loaded in the agent, public key not added to GitHub/GitLab, multi-account key routing with ~/.ssh/config, deploy key limits, and wrong remote URLs — with ssh -v diagnostics.