If you've used Railway.io for more than a week, you've probably experienced the special frustration of a deployment that looks like it worked — green checkmark, no errors — but your app is completely unreachable. No traffic. No response. Just silence.
Most of the time it comes down to a config mistake that Railway doesn't loudly flag. Here are the five that get developers most often, with exact fixes for each.
1. Hardcoding the PORT
This is the #1 Railway gotcha and it catches almost everyone at least once.
Railway injects a $PORT environment variable dynamically at runtime. Your app must read and listen on that port. If you hardcode port 3000 or 8080, your service starts fine but never receives traffic — Railway is sending requests to a port your app isn't listening on.
Broken:
{
"variables": {
"PORT": "3000"
}
}
Setting PORT as a static variable doesn't help — Railway's injected value overrides it anyway.
Fixed — in your app code:
const port = process.env.PORT || 3000;
app.listen(port);
Fixed — in a Dockerfile:
# Don't do this:
EXPOSE 3000
# Do this — let Railway set the port at runtime:
CMD ["node", "server.js"]
# And in server.js: app.listen(process.env.PORT)
This applies to every language and framework. Python with Flask, Go with net/http, Ruby with Puma — they all need to bind to process.env.PORT (or the equivalent env var read in your language).
2. Using an Invalid Builder Value
Railway supports four builders: nixpacks, dockerfile, heroku, and railpack. That's it. If you write anything else — "node", "auto", "docker" — Railway either ignores it or fails silently.
Broken:
{
"build": {
"builder": "node"
}
}
Fixed:
{
"build": {
"builder": "nixpacks"
}
}
If you're using Railway's newer Metal infrastructure, you're likely moving to Railpack (the successor to Nixpacks). In that case, use a railpack.json file with the correct providers array instead:
{
"$schema": "https://schema.railpack.com",
"providers": ["node"],
"deploy": {
"startCommand": "node server.js"
}
}
3. No Restart Policy — Crashed Services Stay Down
By default, if your service crashes Railway won't automatically restart it. You need to explicitly set restartPolicyType.
Broken (service stays dead after a crash):
{
"deploy": {
"startCommand": "node server.js"
}
}
Fixed:
{
"deploy": {
"startCommand": "node server.js",
"restartPolicyType": "ON_FAILURE"
}
}
Valid values are ON_FAILURE, ALWAYS, and NEVER. For most production services you want ON_FAILURE. Using ALWAYS means Railway will restart even intentional shutdowns — usually not what you want.
4. Missing or Broken healthcheckPath
If you define a healthcheckPath, it must start with a /. If it doesn't, Railway either rejects the config or the health check never passes — causing your service to restart in a loop.
Broken:
{
"deploy": {
"healthcheckPath": "health"
}
}
Fixed:
{
"deploy": {
"healthcheckPath": "/health"
}
}
Also make sure that route actually exists in your app and returns a 200 status. A common mistake is defining /health in the config but forgetting to add the route handler in the code.
If you're not ready to implement a health endpoint, remove the healthcheckPath field entirely rather than leaving it broken — Railway will fall back to basic process monitoring.
5. npm install Instead of npm ci in Build Steps
This one is subtle but causes non-deterministic builds — meaning your app works locally and in one deployment but breaks in the next.
npm install can silently upgrade packages within the ranges defined in package.json. npm ci installs exactly what's in your package-lock.json — no surprises.
Broken (nixpacks.toml):
[phases.install]
cmds = ["npm install"]
Fixed:
[phases.install]
cmds = ["npm ci"]
Broken (railpack.json):
{
"steps": {
"install": {
"cmds": ["npm install"]
}
}
}
Fixed:
{
"steps": {
"install": {
"cmds": ["npm ci"]
}
}
}
Same rule applies to Dockerfiles — RUN npm ci instead of RUN npm install.
Catching These Automatically
These five mistakes are easy to make and annoying to debug because Railway doesn't always give you a clear error message. I got tired of finding them manually so I built Railway DevTools — paste your config and Claude AI audits it instantly, flags issues by severity, and shows you the exact fix.
It supports railway.json, railway.toml, Dockerfile, nixpacks.toml, railpack.json, and Procfile. Free to try with no sign-up.
Summary
| Mistake | Symptom | Fix |
|---|---|---|
| Hardcoded PORT | App unreachable | Read process.env.PORT
|
| Invalid builder | Build fails silently | Use nixpacks, dockerfile, or heroku
|
| No restart policy | Crashed service stays down | Set restartPolicyType: ON_FAILURE
|
| Bad healthcheckPath | Restart loop | Start path with /
|
| npm install vs npm ci | Non-deterministic builds | Use npm ci
|
If you've run into other Railway gotchas that aren't on this list, drop them in the comments — I'll add them to the article and potentially to the validator too.
Top comments (0)