Leaving Railway When the $5 Trial Runs Out: Nixpacks to Dockerfile
Railway is the platform people fall for in an afternoon: push, watch it build, click to add Postgres. Then the one-time $5 trial credit runs out. What happens next is a choice between paying $5 a month (a fair price for what you get) and moving. This guide is for the second option, written to be honest about the first.
Railway's pricing, as it is now
- Trial: a one-time $5 credit, usable for up to 30 days, no card.
- Free plan afterwards: $1 of usage credit a month. Enough for a tiny service that is mostly idle, not for a database and an app.
- Hobby: $5 a month, which includes $5 of usage. CPU, memory, volumes and egress are metered on top, so a small app and a Postgres often land near the included amount and a busy one goes past it.
- Builds use Nixpacks by default; Dockerfiles are supported and used when present.
Stay on Railway if $5 a month is fine and you like always-on services with metered pricing and one-click databases. Move if you want an app that costs nothing while idle, or you have several small services and would rather not watch a usage meter.
What is different on the other side
| Railway (Hobby) | SnapDeploy (free tier) | |
|---|---|---|
| Cost model | $5/month plus metered usage | $0; 4 containers, 100 container-hours a month, counted while awake |
| Idle behaviour | Runs and meters, unless you enable app sleeping | Sleeps after 15 minutes without traffic, wakes in about 60 seconds |
| Build | Nixpacks or Dockerfile | Generated Dockerfile (Node, Python, Java, Go, PHP, Ruby, static) or your Dockerfile |
| Database | Metered Postgres/MySQL/Redis/Mongo | PostgreSQL/MySQL/MariaDB/MongoDB Mini $29/month, Redis Mini $12, or a $1 DB Sprint Pack for 12 hours; free external databases work too |
| Volumes | Persistent volumes | None on containers; the filesystem is ephemeral (databases have persistent storage) |
| Private networking | Services talk over a private network | Containers reach each other over their public HTTPS URLs |
| Cron | Cron schedules per service | No scheduler; run periodic work in-process (it only runs while awake) or trigger it from outside |
| Custom domain | Yes | Always-On only ($12/month per container) |
The two rows that decide most migrations are volumes and private networking. If your app writes files it expects to keep, or your services find each other by internal hostname, plan for object storage and public URLs before you start.
Step 1: replace Nixpacks with a Dockerfile
Nixpacks inferred your build from the repository. A Dockerfile makes the same decisions explicit and portable. For a Node service the mapping is direct; the start script becomes the CMD:
FROM node:22-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --omit=dev
COPY . .
ENV NODE_ENV=production
EXPOSE 3000
CMD ["npm", "start"]If you would rather not write one, push without it: SnapDeploy generates a Dockerfile for Node.js, Python, Java, Go, PHP, Ruby and static sites. For anything with native dependencies, a specific runtime version or a multi-step build, write the Dockerfile; it is fifteen lines and you will never wonder what the builder guessed.
Keep reading the port from PORT. Railway sets it and so does SnapDeploy.
Step 2: export the variables
The Railway CLI prints a service's variables in one command, which beats copying from the dashboard:
railway link
railway variables --json > railway-vars.jsonGo through the file before pasting anything. Railway-provided values (RAILWAY_*, PORT, and internal hostnames ending in .railway.internal) must not be copied; they describe Railway's network. Everything else goes into the new container's environment variables by hand. Delete the JSON file afterwards; it contains your secrets.
Step 3: move the database
Railway's Postgres has a public connection URL under the service's Connect tab (the TCP proxy). Dump with it and restore into the new database:
pg_dump --no-owner --no-privileges "$RAILWAY_PUBLIC_DATABASE_URL" > backup.sql
psql "$NEW_DATABASE_URL" < backup.sqlFor Redis, do not migrate: a cache repopulates itself. For a Railway volume, download its contents while the service still runs and upload them to an S3-compatible bucket; then change the app to read from the bucket. That is the one step with real work in it.
Step 4: deploy, test, then stop paying
- Push the Dockerfile. In SnapDeploy: Containers → Deploy from GitHub → pick the repository → add the variables → deploy. First build: a few minutes.
- If two services talked over
*.railway.internal, point them at each other'scontainers.snapdeploy.appURLs and make sure the calls are authenticated, since those URLs are public. - Run the app for a day. Watch for the three usual breakages: a hard-coded port, a trusted-host list without the new hostname, and a file written to disk that was expected to persist.
- Remove the Railway services once the new ones have been up for a week. Downgrade the plan after the last service is gone, not before.
Before you move: Railway's own idle option
If the only problem is the meter, Railway has a setting that stops charging while a service is idle: app sleeping, which shuts the service down after a period without traffic and restarts it on the next request. It turns Railway's cost model into something closer to a free container tier, with the same trade-off of a cold start for the first visitor. For a single low-traffic service that keeps you inside the $5 the Hobby plan includes, that may be all you need. The migration below is for when it is not: several services, a database that costs more than the app, or a preference for a $0 idle bill rather than a small one.
Test the image before the first deploy
docker build -t api .
docker run --rm -p 3000:3000 -e PORT=3000 --env-file .env.local api
curl -i http://localhost:3000/healthUse an env file that contains the values from railway-vars.json minus the Railway-specific ones; if the app boots locally with that file, it will boot on the container host with the same values. Nixpacks quietly installed system packages your Dockerfile now has to name explicitly, and this is where you find out which ones (usually image libraries or a database client).
Where free stops on the other side
- Four containers, 512 MB and 0.25 vCPU each, 100 container-hours a month counted while awake. Railway's Hobby resources are larger; the trade is money for headroom.
- Sleeping after 15 minutes without traffic, about a minute to wake. If a service has to answer at any hour, Always-On is $12/month per container.
- No persistent volumes on containers and no cron scheduler; databases have persistent storage, and periodic work runs while the app is awake or from an external trigger.
- Custom domains only on Always-On.
Sources: Railway plan facts from railway.com/pricing and the Railway docs as of September 2026; SnapDeploy numbers from the free tier docs and add-on pricing. The Railway alternative page keeps the side-by-side table current.