Heroku → Railway
Move a Heroku application to Railway with explicit handling for process types, databases, add-ons, variables, storage, jobs, domains, observability, deployment behavior, and rollback.
Should you make this move?
Both platforms have a case. Compare what you gain with what you give up before scheduling the cutover.
Heroku
- Git-based deploys, buildpacks, and add-ons offer an exceptionally approachable platform
- Managed deployments reduce infrastructure and release-management work
- Pricing and infrastructure control become limiting as applications grow
- Runtime assumptions, platform services, and pricing models shape the architecture
Railway
- Fast service and database provisioning gives developers a low-friction application platform
- Managed deployments reduce infrastructure and release-management work
- Usage pricing and infrastructure abstraction can become limiting at scale
- Runtime assumptions, platform services, and pricing models shape the architecture
Railway: Fast service and database provisioning gives developers a low-friction application platform. This removes a major source-side concern: Pricing and infrastructure control become limiting as applications grow.
What you lose: Git-based deploys, buildpacks, and add-ons offer an exceptionally approachable platform. What you inherit: Usage pricing and infrastructure abstraction can become limiting at scale.
Jump to a section
Know the shape of the move.
This timeline assumes
- One app with web, worker, scheduled jobs, Postgres, and common add-ons.
- The simple Railway guide supports one Procfile process; multi-process apps are modeled as services.
- Ephemeral filesystem assumptions are removed.
- Production data receives a tested backup and restore.
- Heroku stays intact through a stable rollback window.
How do I migrate from Heroku to Railway?
Deploy the repository to Railway, review imported variables, and configure each web, worker, and scheduled process. Move databases and replace add-ons with explicit ownership. Test the application and background jobs against a restored database. Freeze writes for the final data pass, then change domains only after reconciliation and rollback checks pass.
What survives the move.
“Partial” and “manual” are not footnotes. They are work that must be scheduled and verified.
| Item | Outcome | Impact | What happens | Mitigation |
|---|---|---|---|---|
| Application source | clean | critical | Railway deploys the same repository or local source. | Build the exact production commit. |
| Procfile web process | partial | high | Railway supports Procfiles, but its simple guide notes one process. | Create separate services for web, worker, and other processes. |
| Config vars | partial | critical | Railway can import Heroku variables, but scope and generated values require review. | Classify, rotate secrets, and validate service references. |
| Heroku Postgres | manual | critical | Database migration is separate from the simple app guide. | Dump/restore or replicate with measured write freeze and reconciliation. |
| Add-ons | lost | critical | Marketplace resources and credentials do not transfer automatically. | Choose and test one replacement per add-on. |
| Scheduled jobs | manual | high | Heroku Scheduler configuration is not application source. | Recreate timing, timezone, concurrency, and alerts. |
| Domains and TLS | manual | critical | Custom domains and certificates require destination setup and DNS cutover. | Pre-provision hostname, TLS, and rollback records. |
| Buildpacks and stack behavior | partial | critical | Detection, OS packages, release commands, and runtime versions can differ. | Pin runtime and dependencies and test release phase behavior. |
| Logs, metrics, and alerts | lost | high | Historical operational data remains in Heroku/add-ons. | Export required evidence and rebuild monitors. |
| Filesystem data | lost | critical | Runtime local files are not a portable durable store. | Move required files to object storage and verify references. |
Where each thing goes.
| Source | Destination | Method | Notes |
|---|---|---|---|
| Heroku app | Railway project | manual | Group related services. |
| web dyno | Web service | transform | Set start command and health check. |
| worker dyno | Worker service | manual | Separate from web. |
| Config var | Service/project variable | transform | Review scope and rotate. |
| Heroku Postgres | Railway Postgres or external database | manual | Use dump/restore or replication. |
| Add-on | Railway service or external provider | manual | No universal mapping. |
| Scheduler job | Cron job | manual | Preserve timezone and concurrency. |
| Custom domain | Railway domain | manual | Switch DNS after TLS passes. |
Make the move recoverable.
Create the source-of-truth backup
Preserve code, data, configuration, add-on state, and recovery evidence.
- Inventory dynos, processes, releases, buildpacks, vars, databases, add-ons, domains, drains, jobs, storage, and integrations.
- Tag the production commit and export configuration names.
- Create and restore-test database and file backups.
- Export required logs, metrics, and add-on data.
- Record DNS and rollback values.
Proof to capture: A manifest covers every process, secret consumer, data store, job, domain, and integration with restore evidence.
Service topology
Split Heroku process types into explicit Railway services.
- Map web, worker, release, and cron behavior.
- Set dependencies and health checks.
- Test scaling and restart.
Proof to capture: Save the input, output, command or tool settings, warnings, and final item counts.
Data and add-on replacement
Move durable state without hidden dependencies.
- Choose replacements.
- Rehearse data copy.
- Reconcile counts and application scenarios.
Proof to capture: Save the input, output, command or tool settings, warnings, and final item counts.
The things most likely to hurt.
These are operating limits. Treat every “Stop if” condition as a blocked migration, not a suggestion.
Only the web process moves
Workers or release tasks are absent.
- Consequence
- Queues stop and deploys leave schema inconsistent.
- Mitigation
- Model every process explicitly.
Stop if: Any production process has no destination.
Database writes diverge
Both databases accept writes.
- Consequence
- Orders or records split.
- Mitigation
- Use one write authority and reconcile final delta.
Stop if: A write lands outside the declared primary.
Imported variables expose or mis-scope secrets
A service can read unrelated secrets.
- Consequence
- Credential exposure.
- Mitigation
- Rotate and scope variables per service.
Stop if: Any untrusted service reads production secrets.
Do the work in this order.
- Days 1–3 · inventory
Inventory
10–16 hours active3 days elapsedOwner review waiting- Inventory topology and state.
- Choose replacements and rollback.
Depends on: Heroku and Railway admins
Stop / go checkpointBuild?
Go when: Every process and store is mapped.
Stop when: Critical state or add-on is unknown.
- Days 4–5 · backup
Backup and restore
6–10 hours active2 days elapsedBackup transfer waiting- Create backups.
- Run restore drill.
Depends on: Inventory
Stop / go checkpointPilot?
Go when: Data restores and manifests reconcile.
Stop when: Recovery fails.
- Days 6–10 · pilot
Build destination
12–22 hours active5 days elapsedBuilds and DNS waiting- Deploy services and variables.
- Restore data and add-ons.
- Test jobs and health.
Depends on: Backup
Stop / go checkpointRehearse?
Go when: All scenarios and monitors pass.
Stop when: Any process or state is wrong.
- Days 11–14 · rehearse
Cutover rehearsal
4–9 hours active4 days elapsedData copy timing waiting- Measure final data copy.
- Practice DNS and rollback.
- Load-test critical paths.
Depends on: Pilot
Stop / go checkpointCut over?
Go when: Window and rollback meet target.
Stop when: Data loss or downtime exceeds approval.
- Days 15–20 · cutover
Freeze and observe
3–13 hours active3–6 days elapsedDNS and production signals waiting- Freeze writes.
- Copy final data.
- Switch DNS and jobs.
- Observe.
Depends on: Rehearsal
Stop / go checkpointClose rollback?
Go when: Data, traffic, jobs, and alerts pass.
Stop when: Critical errors or divergence appears.
Cut over with a way back.
Cutover
Move production traffic and writes to Railway with one authoritative datastore.
- Freeze deploys and writes.
- Create final backups and copy data.
- Deploy the approved commit.
- Switch domains, jobs, workers, and integrations.
- Run smoke and reconciliation checks.
- Keep Heroku scaled and recoverable.
Proof to capture: Railway serves production, data reconciles, workers/jobs run once, and monitors pass.
Rollback
Return traffic and writes to Heroku.
- Stop Railway writes and jobs.
- Capture destination deltas.
- Restore or apply approved data to Heroku.
- Restore DNS, workers, scheduler, and integrations.
- Run smoke checks.
Proof to capture: Heroku again owns traffic and data with current approved records.
- Data mismatch
- Critical process absent
- Error or latency threshold exceeded
- Job duplication
- Secret/access failure
Prove the migration worked.
Every blocking check must pass. Capture the evidence before cleanup begins.
| Pass | ID | Check | Method | Expected result | Evidence |
|---|---|---|---|---|---|
V-01Blocking | Production commit | Compare release SHA and dependencies. | Exact approved source. | Release record. | |
V-02Blocking | Web, worker, release, cron | Exercise each process. | One healthy instance path. | Process log. | |
V-03Blocking | Database reconciliation | Compare counts, checksums, and scenarios. | No unexplained variance. | Data report. | |
V-04Blocking | Replacement behavior | Trigger each dependency. | Approved result. | Dependency log. | |
V-05Blocking | Variables and secrets | Audit scope and runtime access. | Least privilege and correct values. | Config audit. | |
V-06Blocking | DNS and TLS | Resolve and inspect certificates. | Correct target and valid TLS. | DNS/TLS output. | |
V-07Blocking | Logs and alerts | Generate known events. | Logs arrive and alerts fire once. | Alert log. | |
V-08Blocking | Rollback | Run rehearsal or isolated restore. | Recovery meets target. | Recovery report. |
Remove the scaffolding safely.
Safe after: Seven stable days and one successful deploy plus scheduled-job cycle.
- Archive backups and evidence.
- Revoke Heroku tokens and drains.
- Remove obsolete add-ons only after retention review.
- Keep Heroku intact through rollback window.
- Update operations documentation.
- Schedule restore and secret reviews.
When the plan met reality.
First-hand accounts are preferred. Vendor case studies are labeled, and every note below is an editorial paraphrase—follow the link for the full context.
Paul Works migrated a small Rails API and its JawsDB MySQL database from Heroku to Railway in roughly 20–30 minutes without downtime. A streaming database command avoided an intermediate dump file, and the monthly cost fell from about $20 to about $6. The report is intentionally small-scale, but it captures the complete path from application deployment and environment variables through database transfer and verification.
- Rehearse the database streaming command and confirm destination connectivity before using it against the final production data.
- Verify application health and representative database reads on Railway before redirecting traffic or deleting Heroku resources.
- For this compact Rails service, the database transfer—not application deployment—was the step most likely to complicate the move.
- The reported 70% saving is specific to a small workload and should be recalculated against production usage rather than generalized.
Verify against the primary material.
Platform behavior changes. Check these sources and the review dates above before executing a production migration.
- Railway: migrate from HerokuAccessed 2026-07-19
- Heroku: export Postgres dataAccessed 2026-07-19
- Railway: databasesAccessed 2026-07-19