Versioning Railway Deployments with railway.json
Learn how to move Railway service configuration from the dashboard into a version‑controlled railway.json file to eliminate drift, automate builds, and keep secrets safe.
10 Aug 2026, 17:36 UTC

The Dashboard Drift Problem
Many developers start with Railway by clicking buttons in the web UI to set environment variables, change start commands, or configure health checks. While fast, this creates a visibility gap: your infrastructure state exists only in the platform's database, not in your git history. When a teammate joins the project or you need to spin up a staging environment, you are forced to manually replicate those settings, leading to "dashboard drift" where production and staging diverge in undocumented ways.
Defining the Deployment Lifecycle
Railway uses railway.json to override the default behavior of its build system (typically Nixpacks). While Nixpacks is excellent at guessing your language and runtime, explicit configuration removes the guesswork and prevents "it works on my machine" failures during the build phase.
Build and Start Commands
The most critical parts of the configuration are the build and start commands. The build command handles dependency installation and compilation, while the start command defines the entry point for the production process. Defining these explicitly ensures that you aren't relying on a package.json script that might be changed for local development purposes.
Health Checks
To prevent downtime during a rollout, you can define a health check endpoint. Railway will monitor this path; if the new deployment fails to return a successful response, the platform can prevent the traffic switch, effectively acting as a safety net for broken releases.
Practical Configuration Example
Consider a Node.js application that requires a specific build step to generate static assets and a custom start command to run a production server. Instead of configuring these in the UI, create a railway.json file in your root directory.
{
"$schema": "https://railway.app/railway.schema.json",
"build": {
"builder": "NIXPACKS",
"buildCommand": "npm run build"
},
"deploy": {
"startCommand": "npm run start:prod",
"healthCheckPath": "/api/health",
"restartPolicyType": "ON_FAILURE"
}
}
Implementation Details
- Location: Place this file in the root of your repository.
- Permissions: No special permissions are required; the Railway build bot reads this file during the build phase.
- Expected Result: Upon the next
git push, the Railway logs will show the custombuildCommandexecuting instead of the default Nixpacks detection. - Risk: A syntax error in the JSON file can cause the build to fail immediately. Validate your JSON before committing.
Managing Secrets and Variables
A common mistake when moving to Infrastructure-as-Code (IaC) is attempting to put API keys or database passwords directly into railway.json. Never do this. The railway.json file is committed to version control and is visible to anyone with repository access.
The correct pattern is a hybrid approach: use railway.json for structural configuration (how to build/run) and the Railway Dashboard's encrypted environment variable store for sensitive configuration (secrets). You can still manage these variables via the Railway CLI for automation, but they should remain decoupled from the JSON configuration file.
Trade-offs and Limitations
| Approach | Pros | Cons |
|---|---|---|
| UI-Based Config | Instant changes, no commit needed. | No history, prone to human error during replication. |
| railway.json | Versioned, reproducible, transparent. | Requires a commit/push to apply changes. |
One significant limitation is that any change to railway.json triggers an immediate redeployment of the associated services. In a large microservices architecture, a small change to a shared config pattern could trigger a cascade of rebuilds. Plan your commits to group configuration changes together.
Verification Checklist
- Build Log Audit: Check the "Deployments" tab in Railway. Confirm that the
buildCommandlisted in the logs matches exactly what you wrote in your JSON file. - Health Check Validation: Trigger a deployment and monitor the status. If the service stays in "Deploying" and then rolls back, verify that your
healthCheckPathis actually returning a 200 OK status. - Environment Isolation: Change a variable in the Dashboard for your "Production" environment and verify that your "Staging" environment remains unaffected, confirming that your
railway.jsonis handling the logic while the platform handles the environment-specific data.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.