
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.

Migration · Railway → Skiffly
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.
Export, deploy, cut over. The terminal below is the whole move, end to end.

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

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

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.

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

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

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.
# 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 recordsskiffly up, skiffly logs -f, skiffly variables set, skiffly domain, skiffly connect. Same names as the Railway CLI where the feature exists.
Point Claude Code, Cursor or Codex at the Skiffly MCP server and let the agent do the move: skiffly mcp install claude. Tool names mirror the Railway MCP server.
projects, deployments(input:), variables, serviceInstanceUpdate, templateDeployV2 and the other compatible fields work as they are. Change the endpoint and the token.
A railway.ts from railway/iac becomes .skiffly/skiffly.ts with defineRailway → defineSkiffly. Everything else keeps its name.
$PORT (default 8080 when unset).*.railway.internal or IPv6 private networking.
One app and one database without a card to test the build. Top up when you are ready to cut over.