Skip to content

Migration · Railway → Skiffly

From Railway to Skiffly in three steps.

The concepts map one to one: workspace, project, environment, service, ${{Postgres.DATABASE_URL}}. Most API documents run unchanged and the CLI commands share their names. What changes is who you pay and where your data lives.

Three steps

  1. 1

    Export what Railway knows

    Variables per service with railway variables --kv; a pg_dump of each database. Drop the RAILWAY_* entries: Skiffly provides the SKIFFLY_* equivalents.

  2. 2

    Deploy on Skiffly

    skiffly init in each repository, then skiffly up. Set the variables, deploy the Postgres template, restore the dump through skiffly connect.

  3. 3

    Move the domain

    Test on the generated *.skiffly.cloud domain, add the custom domain, switch the CNAME when the certificate is issued. Keep Railway running until DNS has propagated.

terminal
# 1. export
railway variables --kv > vars.env
pg_dump "$RAILWAY_DATABASE_URL" -Fc -f db.dump

# 2. deploy
skiffly init && skiffly up
skiffly deploy --template postgres
skiffly connect postgres --print       # → pg_restore -d <url> db.dump
skiffly variables set --skip-deploys $(grep -v '^RAILWAY_' vars.env | xargs)
skiffly variables set 'DATABASE_URL=${{Postgres.DATABASE_URL}}'
skiffly redeploy

# 3. cut over
skiffly domain app.example.com         # prints the CNAME + TXT records

Before you cut over

Compare with Railway
  • The app listens on $PORT (default 8080 when unset).
  • No dependency on *.railway.internal or IPv6 private networking.
  • Outbound SMTP on port 25 is blocked; use 587 with authentication.
  • Plan limits: Hobby 8 GB / 8 vCPU per service, Pro 32 GB / 32 vCPU.
  • PR previews are enabled per project; forks are ignored.

Start the move on the free tier

One service without a card to test the build. Top up when you are ready to cut over.