21 days ago
Our Medusa backend builds are consistently failing on Railway with 429 Too Many Requests errors from the npm registry (registry.npmjs.org). The same build succeeds locally, so this appears to be IP-based rate limiting affecting Railway's shared build egress.
Error details
During pnpm install, we get:
ERR_PNPM_FETCH_429 GET https://registry.npmjs.org/@medusajs%2Fjs-sdk: Too Many Requests - 429
This error happened while installing the dependencies of @medusajs/draft-order@2.17.2
The affected packages are Medusa core packages (@medusajs/js-sdk, @medusajs/types, @medusajs/modules-sdk), which are heavy dependencies of the Medusa backend.
What we have tried
Multiple redeploys from the latest source.
Adding retry and timeout settings to .npmrc:
fetch-retries=5
fetch-retry-mintimeout=20000
fetch-retry-maxtimeout=120000
fetch-timeout=300000
prefer-offline=true
Confirmed the lockfile (pnpm-lock.yaml) is committed and up to date.
Why we believe it is Railway-side rate limiting
The exact same build completes successfully on our local machine in ~51 seconds, downloading the same 1,427 packages. The only difference is the egress IP used by the Railway build environment versus our local network.
Request
Could you help us with one of the following?
Persistent package cache — Is it possible to enable a persistent pnpm store/cache across builds so we do not hit the npm registry on every deploy?
Build IP rotation / alternative region — Can we route the build through a different region or IP to avoid the currently rate-limited shared IP?
Registry mirror support — Do you support or recommend a private registry mirror (e.g., Verdaccio) to cache npm packages?
Immediate mitigation — Any other short-term workaround you can apply on your side.
Project/service details are available in our Railway dashboard. Let me know if you need deployment IDs or further logs.
Pinned Solution
18 days ago
What we tried:
- Increasing fetch-retries and fetch-timeout
- Reducing network-concurrency
- Caching the pnpm store mount in the Dockerfile
It all helps, but the initial build still needs to download the packages. And if the Railway IP is already rate-limited, the cache doesn't help.
The solution that worked
We switched to building the Docker image in GitHub Actions and publishing it to the GitHub Container Registry (GHCR). Railway then deployed using the ready-made image, without needing to run npm commands.
Workflow summary:
- We created a multi-stage Dockerfile with a cache mount for the pnpm store.
- We created a
.github/workflows/docker-build.ymlworkflow that builds and pushes the image upon every merge to themasterbranch. - We configured Railway to deploy from:
ghcr.io/your-username/medusa-backend:master
9 Replies
21 days ago
This thread has been opened as a bounty so the community can help solve it.
Status changed to Open Railway • 21 days ago
21 days ago
The 429s happen because pnpm downloads a ton of packages in parallel and railways build ips are shared, so npm's rate limiter trips.
add network-concurrency=6 to your .npmrc and the burst goes away, install is a bit slower but no more 429s. keep your retry settings, they stack fine.
the bigger win is to stop pulling 1427 packages on every deploy. railway supports buildkit cache mounts in dockerfiles, which is basically the persistent pnpm store you can ask for something like :
RUN --mount=type=cache,id=pnpm-store,target=/pnpm/store pnpm install --frozen-lockfile
first good build fills the cache and after that you barely hit the registry at all. heads up that railway wants a specific id format for the cache mount (it includes your service id), the exact syntax is in their build docs.
once thats in place the shared ip thing mostly stops mattering, and you dont need verdaccio or a mirror
21 days ago
We're in the same situation since yesterday, we're using bun but I guess that doesn't quite matter since both are just running HTTP requests to the npm registry. It happens on most of our builds, occasionally one passes but it's killing most of our builds at this point.
The cache suggestion is a good one, but that doesn't quite explain why this would suddenly happen, we've been running this service and have been spamming plenty of builds in short notice for more than a year.
20 days ago
- npm config set registry https://registry.npmmirror.com
- Wait for fix from Medusa devs
- change registry back to default: npm config set registry https://registry.npmjs.org/
Hope it will help
18 days ago
tossivahva
1. **npm config set registry https://registry.npmmirror.com** 2. Wait for fix from Medusa devs 3. change registry back to default: **npm config set registry https://registry.npmjs.org/** Hope it will help
18 days ago
if you consider advicing people to use an unknown third party registry to install dependencies for their (possibly) production software a good solution, you either have malicious intent or must be taking the short bus to school.
robbyuitbeijerse
if you consider advicing people to use an unknown third party registry to install dependencies for their (possibly) production software a good solution, you either have malicious intent or must be taking the short bus to school.
18 days ago
This is just China mirror from Alibaba as I know. No malicious intention from me. I will edit my post later how I solve this without third party registry mirror.
18 days ago
What we tried:
- Increasing fetch-retries and fetch-timeout
- Reducing network-concurrency
- Caching the pnpm store mount in the Dockerfile
It all helps, but the initial build still needs to download the packages. And if the Railway IP is already rate-limited, the cache doesn't help.
The solution that worked
We switched to building the Docker image in GitHub Actions and publishing it to the GitHub Container Registry (GHCR). Railway then deployed using the ready-made image, without needing to run npm commands.
Workflow summary:
- We created a multi-stage Dockerfile with a cache mount for the pnpm store.
- We created a
.github/workflows/docker-build.ymlworkflow that builds and pushes the image upon every merge to themasterbranch. - We configured Railway to deploy from:
ghcr.io/your-username/medusa-backend:master
Status changed to Solved dluan • 18 days ago
manuproject
The 429s happen because pnpm downloads a ton of packages in parallel and railways build ips are shared, so npm's rate limiter trips. add network-concurrency=6 to your .npmrc and the burst goes away, install is a bit slower but no more 429s. keep your retry settings, they stack fine. the bigger win is to stop pulling 1427 packages on every deploy. railway supports buildkit cache mounts in dockerfiles, which is basically the persistent pnpm store you can ask for something like : RUN --mount=type=cache,id=pnpm-store,target=/pnpm/store pnpm install --frozen-lockfile first good build fills the cache and after that you barely hit the registry at all. heads up that railway wants a specific id format for the cache mount (it includes your service id), the exact syntax is in their build docs. once thats in place the shared ip thing mostly stops mattering, and you dont need verdaccio or a mirror
18 days ago
Thanks for the suggestions; I saw some improvements, but it wasn't enough to solve the problem. In the end, I had to work around the installation via the GitHub image.
Status changed to Awaiting Conductor Response Railway • 18 days ago
robbyuitbeijerse
We're in the same situation since yesterday, we're using `bun` but I guess that doesn't quite matter since both are just running HTTP requests to the npm registry. It happens on most of our builds, occasionally one passes but it's killing most of our builds at this point. The cache suggestion is a good one, but that doesn't quite explain why this would suddenly happen, we've been running this service and have been spamming plenty of builds in short notice for more than a year.
18 days ago
Hi Robby, unfortunately, I had to work around the installation using GitHub; I’ve posted the steps I took to do that below. I hope this helps you too.
Status changed to Solved dev • 18 days ago
