Migrate from Heroku to Coolify: what the move involves
Whether the trigger is a renewal, a pricing change, a data residency requirement or simple lock-in, the move from Heroku to Coolify is a rebuild of your builds, data and configuration on servers your team operates. Nothing carries over as a copy. Each app needs a build path that Coolify can run, each Heroku Postgres database needs a restore into a Coolify-managed PostgreSQL instance, and each config var needs to be recreated as a Coolify environment variable. Plan the work as three workstreams that run in parallel and converge at cutover. The platform or DevOps team usually does this work, sometimes with an implementation partner for the server build, hardening or cutover. Heroku classic buildpacks do not carry over unchanged. Coolify's build packs are Nixpacks, Railpack (beta), Static, Dockerfile and Docker Compose, plus a Docker Image method, so each app either auto-detects into Nixpacks or Railpack or gets a Dockerfile that you write and test. Start with an inventory of every app's Procfile, buildpack list and runtime version, and flag the apps that depend on buildpack-specific behavior.
On effort and risk, the largest variables are the number of apps, how many use custom buildpacks, how large the databases are and how much of the operational work you want to take on. Confirm the target server sizes against Coolify's installation requirements before you order hardware, and confirm the backup and restore path for each database with a test restore, not only a successful dump. Coolify's own guidance for teams coming from managed platforms recommends deploying without changing production DNS, testing on a temporary domain, and keeping the old platform available until the new deployment is stable. Keep Heroku running through that window, and agree in writing who owns backups, patching and rollback once Heroku is switched off.
Which Heroku capabilities map cleanly to Coolify
This table maps each Heroku capability used in a typical app to its Coolify equivalent and labels it clean, needs rework or gap. Read the status column first, then the notes, to see which items need design work before cutover. The main takeaway is that the app code usually moves cleanly, while buildpacks, scheduled jobs, pipelines and Redis backups need separate planning.
| Heroku capability | Coolify equivalent | Status and notes |
|---|---|---|
| Git push deploys | Git-based application deploys from a connected repository | Clean. Connect the repository and branch in Coolify; the push-to-deploy trigger must be configured again. |
| Heroku buildpacks | Nixpacks, Railpack (beta), Static, Dockerfile or Docker Compose build packs | Needs rework. Coolify does not run classic Heroku buildpacks, so choose auto-detection or add a Dockerfile. |
| Procfile process types | Separate Coolify applications or Docker Compose services per process | Needs rework. Each web or worker process must be defined as its own service with its own start command. |
| Config vars | Resource environment variables with build-time, runtime and preview scopes | Clean with checks. Re-create each variable, set the scope correctly, and confirm build-time values are not secrets exposed in logs. |
| Heroku Postgres | PostgreSQL deployed in Coolify, restored from a pg_dump custom or SQL dump | Needs rework. Restore into a Coolify-managed instance and verify extensions, roles and PostgreSQL version. |
| Heroku Data for Redis | Redis or Valkey deployed as a one-click service | Gap. Scheduled backups in Coolify exclude Redis, so plan persistence and backup separately. |
| Preview apps (Review Apps) | Preview deployments for GitHub, GitLab, Gitea and Bitbucket | Needs rework. Requires wildcard DNS for the default preview URL pattern; Heroku Pipelines and Heroku Scheduler need separate handling. |
| Custom domains and TLS | Coolify proxy (Traefik by default or Caddy) with automatic HTTPS | Clean with DNS work. Point domains at the server and confirm certificates issue before the production cutover. |
Which data and integrations to move, and by which documented path
Moving a Heroku app to Coolify is mostly a matter of moving four kinds of state: the Postgres data, the config vars, the uploaded files and the connections that Heroku's add-ons and integrations made for you. Each has a documented path, and each needs its own check before DNS changes. Plan them as separate work items so none is assumed to have come across with the code.
Postgres data through pg:backups
Heroku's pg:backups files use pg_dump's custom format. Download the dump from Heroku, then use Coolify's PostgreSQL Import Backup on the new database, which accepts SQL dumps, custom archives, tar archives and all-database dumps. Confirm the PostgreSQL major version on the Coolify side matches what your app expects, and that row counts and a sample of application queries agree after the restore. Keep the Heroku database running until that check passes.
Config vars and their scopes
Heroku config vars are capped at 64 KB of combined keys and values per app, and you can list them with the heroku config CLI command. Export them to a file that stays out of Git, then recreate each one in Coolify with the scope it needs: build-time for variables the build reads, runtime for the running process, and preview for pull request environments. Build-time values that the app needs inside the image are a common cause of failed first deploys.
Uploaded files on persistent storage
Heroku dynos have an ephemeral filesystem, so user uploads normally live in an external store such as S3. Confirm where your app writes files. If any path writes to local disk, define persistent storage in Coolify before cutover, and copy existing files across. Coolify's migration guide notes that a rollback does not restore persistent files, so treat file copies as a separate, verified step with its own sign-off.
Webhooks and outbound callbacks
Any service that posts to your app, such as payment providers, email event feeds or CI notifications, has the old Heroku hostname in its configuration. List every inbound and outbound endpoint, update each target to the new domain at the same time as the DNS plan, and confirm signing secrets were copied with the config vars. Schedule a short overlap so no event is lost during the switch.
Add-ons and GitHub App connections
Heroku add-ons such as Redis, logging or email services do not move by themselves. Each one needs a replacement, a new credential and an updated connection string. Coolify's GitHub App connection and preview deployment webhooks must also be re-authorized against your repositories. Inventory add-ons from the Heroku dashboard, then mark each one as replaced, retired or kept as an external service.
Backups after the first restore
Heroku handled database backups for you, and the migrated database does not inherit that schedule. Configure Coolify's scheduled PostgreSQL backups, pg_dump custom format, optional S3-compatible upload and retention by count, days or size, before you retire Heroku. Test one restore from a Coolify backup into a scratch database, since an untested backup is not a recovery plan.
The migration sequence from inventory to decommission
This sequence moves a Heroku app and its Postgres data to Coolify in an order that keeps Heroku running until the new deployment has passed every check. Each step ends with a written output, so the cutover is a decision based on evidence rather than a single switch.
Inventory apps, add-ons and config vars
List every app in scope, its process types from the Procfile, each add-on attached to it, and every config var key. Record which add-ons are Heroku Postgres, Heroku Data for Redis or other services, and note any custom domains, scheduler jobs and outbound integrations that depend on a fixed address. The owner signs off the inventory, and the output is a single document that lists each app with its dependencies and a named owner for each item.
Build a pilot app with Nixpacks or a Dockerfile
Choose one low-risk app and deploy it to a Coolify server from its Git repository. Coolify's build packs are Nixpacks, Railpack (beta), Static, Dockerfile and Docker Compose, and Heroku classic buildpacks are not among them, so the team selects Nixpacks auto-detection where it works and writes a Dockerfile where it does not. The engineer who owns the app confirms the build passes and the process starts, and the output is a successful build log plus a note of any Heroku buildpack behavior that had to be rewritten.
Re-create config vars as Coolify environment variables
Copy each config var from the inventory into Coolify's resource variables, assigning the build-time, runtime or preview scope that matches how the app uses it. Heroku caps config vars at 64 KB of combined keys and values per app, so confirm the export from
heroku configis complete before entering values. The engineer compares the key list in Coolify with the Heroku inventory, and the output is a checked list of keys with scopes and no values stored in tickets or chat.Restore the Postgres dump into a Coolify database
Export the database with
heroku pg:backupsin pg_dump custom format, then create a PostgreSQL database in Coolify and use its Import Backup function. Coolify accepts SQL dumps, custom archives, tar archives and all-database dumps, so the custom archive can be loaded directly. The database engineer checks the row counts of the largest tables and runs the application's read paths against the restored copy, and the output is a signed restore record with matching counts for each table checked.Rehearse the restore and the app against it
Repeat the restore at least once against a copy of production data, then run the app's test suite and a scripted set of critical user actions against the restored database. Record how long the restore took and whether any extension, role or schema differences appeared, since these are the usual causes of a failed cutover. The team lead reviews the rehearsal log, and the output is a rehearsal report that lists every difference found and how it was resolved.
Run a parallel deployment on a temporary domain
Deploy each in-scope app to Coolify and test it on a temporary domain while production DNS still points to Heroku. Coolify's guidance is to deploy without changing production DNS, configure variables and persistent storage, and test the new deployment first. Testers exercise logins, payments, email and scheduled jobs, and the output is a test sign-off per app that names any open defect and whether it blocks cutover.
Repoint DNS and keep Heroku available
Lower the DNS record time to live ahead of the change if your DNS provider allows it, then repoint the production domain to the Coolify proxy. Keep the Heroku app running and its database reachable, because rolling back means pointing DNS back and the Coolify database may hold new writes that must be reconciled. Coolify's guidance is to repoint DNS only after the new deployment is stable, so the on-call engineer watches error rates and logs, and the output is a cutover checklist that records the change time, the rollback steps and the sign-off from the app owner.
Decommission Heroku after a stable period
Once the new deployment has run stably for a period the team agreed in advance, take a final pg:backups export from Heroku, store it in your own retained location, and remove the add-ons and dynos. Confirm the retained export can be restored before deleting the Heroku database. Cancel any Heroku billing lines only after the finance owner confirms the last invoice, and the output is a decommission record that holds the final backup location, the restore check result and the date each resource was removed.
What drives cost and duration in a Heroku to Coolify move
This table lists the factors that change the cost and effort of moving Heroku apps to Coolify, with why each one matters and how to keep it down. Coolify itself is free to self-host under Apache-2.0, so most of the spend is servers, backups, patching and staff time. Use the rows to build the scope you put in front of a quote.
| Driver | Why it moves cost or effort | How to keep it down |
|---|---|---|
| App count | Each app needs its own Coolify application, domain, environment variables and deploy check, so effort grows with the number of apps even when each one is small. | Group apps by owner and dependency, move low-risk apps first, and retire unused apps before migration rather than moving them. |
| Buildpack complexity | Heroku classic buildpacks are not offered in Coolify, so each app must build through Nixpacks, Railpack (beta), a Dockerfile or a Docker Compose file. Apps with custom buildpacks or unusual system packages need more rework. | Inventory each app's buildpack list and Procfile first. Apps that already have a Dockerfile or build cleanly with Nixpacks usually need the least work. |
| Database size and restore time | Heroku pg:backups files are pg_dump custom format, and the restore time grows with database size, extensions and index rebuilds. Large databases also lengthen the rehearsal and the cutover window. | Rehearse a restore into a Coolify-managed PostgreSQL on a copy, measure the time, and plan the final cutover around a fresh dump taken close to the switch. |
| Add-ons to replace | Each Heroku add-on, such as Redis, schedulers or logging, needs a replacement service, configuration and a decision on backups. Backups for some Coolify databases are not scheduled, so extra work falls on the operator. | List every add-on per app, map each to a Coolify one-click service or an external option, and decide early which ones you will run yourself. |
| Preview deployments and wildcard DNS | Coolify preview deployments use a {{pr_id}}.{{domain}} pattern that needs wildcard DNS. Setting that up, along with per-preview resources, adds configuration and a DNS change that is not needed for production alone. | Turn previews on only for the apps that use them, and confirm your DNS provider and certificate approach before enabling them. |
| Compliance evidence needs | If auditors or customers ask for records of backups, access, patching and change control, you must collect and retain that evidence from the new platform. The effort depends on what your control framework already requires. | Agree the evidence list before the move. Ask the implementation partner to prepare the controls and records in a form your assessor can review, noting that an independent auditor issues any attestation. |
| Number of servers | Each server needs OS hardening, Docker, the coolify-proxy container, monitoring and patching. Multi-server layouts add placement, networking and failover decisions beyond a single host. | Start with the smallest set of servers that meets your capacity and recovery targets, and document what each server runs. |
| Recurring operating costs | Coolify is free to self-host under Apache-2.0. The recurring costs are the servers you rent or own, backup storage, time spent patching and upgrading Coolify and the OS, and the staff or retainer that covers on-call work. | In a quote, ask for each cost line separately: server and storage fees, backup retention, patch cadence, on-call coverage and who owns each upgrade. |
How the move differs by size and starting point
A single app with one Postgres database is the simplest case. The build is usually the smallest change: Coolify auto-detects many apps with Nixpacks, and a Dockerfile gives you more control if the app depends on system packages that a Heroku buildpack used to supply. The data work is one restore. You take a pg:backups dump in pg_dump custom format and load it into a Coolify-managed PostgreSQL, which accepts custom archives, so the file format does not need converting. Cutover is a single DNS change that you stage.
- Build: Test Nixpacks first, then move to a Dockerfile only if detection fails or the runtime needs something specific.
- Config vars: Re-create the 64 KB or smaller set by hand and mark each as build-time or runtime in Coolify.
- Database: Restore into a new PostgreSQL and compare row counts for a few key tables before you trust it.
- Cutover: Deploy without changing production DNS, test on a temporary domain, then repoint DNS and keep Heroku running until the new deployment is stable.
- Operations: Confirm who will take the next backup and who restores if the server fails.
Before you start, confirm your Heroku Postgres plan size, the app's Procfile process types and whether any add-on besides Postgres is attached.
A team with several apps usually has more add-ons, shared configuration and review apps. Each app becomes its own Coolify application, and the shared work is in standardizing how they build, where secrets live and how databases are grouped. Review apps are the biggest change, because Coolify preview deployments need wildcard DNS and are configured per source repository rather than copied from app.json.
- Build: Expect a mix of Nixpacks and Dockerfile builds, so agree on one pattern per language stack.
- Add-ons: List every Heroku add-on, then map each to a Coolify database, a Redis service or an external provider.
- Preview deployments: Confirm your Git host (GitHub, GitLab, Gitea or Bitbucket), set up the wildcard domain and decide whether previews get their own databases.
- Config vars: Use the same naming across apps so that environment scopes stay consistent.
- Cutover: Move apps in waves so that a single failed app does not block the rest.
Confirm which add-ons are in use, which Git provider hosts the repositories and whether review apps depend on seeded data that must be recreated.
In a regulated environment the technical steps are the same, but the migration must also produce evidence that controls are in place. Heroku's Shield tier and its compliance coverage do not carry over to Coolify, so the operator owns encryption, access control, logging, backup testing and change records. Plan these controls before the first production deploy, not after.
- Build: Pin base images and document the build source, because the image becomes the artifact you must defend in an assessment.
- Data: Document where backups are stored, how long they are kept and how a restore is tested, since Coolify scheduled backups can go to S3-compatible storage you choose.
- Access: Define who can deploy, who can read database credentials and how Coolify API tokens are scoped.
- Evidence: Record the cutover plan, test results and rollback steps. A rollback can redeploy an application image but does not restore databases or persistent files.
- Ownership: Decide which team owns patching the host and Coolify itself.
Confirm with your assessor which control evidence they expect and whether the target server location meets your data residency rules. DeployOpen prepares systems and evidence for assessments, but independent auditors issue any audit report or certification.
What usually goes wrong and how to prevent it
Most failed Heroku-to-Coolify moves fail quietly: a variable is missing, a restore finishes without anyone checking the data, or traffic moves before the app has been tested. The cards below cover the failure points we see most often, paired with a check you can run before cutover.
Missed config vars
Heroku config vars are read with the heroku config CLI command, and they are capped at 64 KB of combined keys and values per app, so a long list is easy to overlook. Variables set through the Heroku dashboard, add-on attachments such as DATABASE_URL, and values used only at build time are the ones most often lost. Compare the full Heroku list against the Coolify resource variables, and confirm each one is set in the correct scope: build-time, runtime or preview. Then run a smoke test that exercises every feature depending on a secret.
Restore without row count checks
A restore command that exits without errors does not prove the data is complete. Import a PGBackups dump into the Coolify-managed PostgreSQL, then compare row counts and key aggregates for the largest tables against the source database, and check sequences and extensions. Record the exact dump file, its size and the PostgreSQL version used for both sides. Treat any mismatch as a blocker, not a warning.
DNS changed before testing
Repointing production DNS before the new deployment has been exercised sends real users to an untested stack. Coolify's guidance is to deploy without changing production DNS, test on a temporary domain, then repoint DNS while keeping the Heroku app available until the new deployment is stable. Plan a rollback path for the period in which both platforms are live, and confirm that writes made during that window are not split between two databases.
Backups never rehearsed
A backup that has never been restored is an assumption. Coolify runs scheduled PostgreSQL backups with retention settings, and a copy stored off the server matters if the host fails. Rehearse a full restore onto a separate server, time it, and confirm the application starts against it. Document who runs the restore, where the backup files live and how long recovery takes, because a rollback in Coolify can redeploy the application image but does not restore databases or persistent files.
Redis data assumed backed up
Coolify deploys Redis, Dragonfly and KeyDB, but its scheduled backups do not cover them. Teams moving from Heroku Data for Redis often assume a cache or queue is protected the same way the Postgres database is. Decide per dataset whether loss is acceptable, such as a cache that can be rebuilt, or whether a persistence and backup plan is needed. Queues and session stores that are lost during cutover can drop jobs or log out users, so confirm this before the move.
Single-server capacity limits
Coolify manages applications across one or more servers over SSH, but a single host that carries the app, database and proxy has a hard ceiling on CPU, memory and disk. Heroku dyno scaling is replaced by sizing your own servers, so load tests should run on the target hardware before cutover. Coolify requires at least 2 CPU cores, 2 GB RAM and 10 GB of free disk, which is a floor, not a sizing guide. Check peak traffic and database connection counts against the server you plan to run.
Lost preview and webhook settings
Heroku Review Apps and GitHub integrations do not carry over automatically. Coolify preview deployments need a GitHub App or webhook, or the equivalent for GitLab, Gitea or Bitbucket, and the default preview URL pattern needs wildcard DNS. Re-create the deploy webhooks, confirm that pull request events reach Coolify, and check that preview deployments are removed when a request closes. Missing webhooks often go unnoticed until a team merges and nothing deploys.
Questions buyers ask before moving Heroku apps to Coolify
How much effort and time does a move from Heroku to Coolify take?
The effort depends on how many apps you run, how much each one depends on Heroku add-ons, and how much of the build is already Docker-friendly. A single stateless web app with one Postgres database and a handful of config vars is a small job. Apps with background workers, scheduled jobs, Redis, file uploads or many add-ons take longer because each dependency needs a home on your servers. Coolify's guide for teams coming from managed platforms describes a sequence: deploy without changing production DNS, configure environment variables and persistent storage, test on a temporary domain, then repoint DNS. Ask any partner to size the work app by app in a written scope, listing the add-ons each app uses and the number of environments you need to replicate.
Can our team migrate Heroku apps to Coolify without outside help?
Many teams can, provided someone on staff is comfortable with Linux server administration, Docker, DNS and PostgreSQL. Coolify's installation requires at least 2 CPU cores, 2 GB RAM and 10 GB of free disk on a supported Linux distribution, and it installs with a single script. The harder parts are not the install. They are backups, patching, monitoring, and the on-call work that Heroku handled for you before. If your team has that capacity, a self-run migration is realistic for simple apps. If not, a fixed-scope engagement from DeployOpen can cover planning, implementation, backup configuration and documentation, with ongoing support available as a retainer.
What does the work require from our engineers and infrastructure?
You need the servers, the Git access and the people who will own them afterward. Coolify connects to each server over SSH and prepares it to run Docker workloads, so you need SSH access, a supported Linux host and a decision on where it runs. Your engineers will set environment variables, confirm persistent storage paths, and check each app after its first deploy. Expect to provide a Git repository per app, the database credentials or dump files, and a DNS owner who can add records and wildcard entries if you want preview deployments. The work also includes owning backup schedules, retention and restore tests, which Heroku did not expose in the same way.
Do Heroku buildpacks work in Coolify?
Heroku's classic buildpacks are not among Coolify's build packs, so existing apps do not move unchanged. Coolify's Git build packs are Nixpacks, Railpack (in beta), Static, Dockerfile and Docker Compose, and it also offers a Docker Image method that skips the build by pulling an existing image. Most standard Node, Python, Ruby or Go apps can be auto-detected by Nixpacks or Railpack, but apps that rely on custom buildpacks or specific system packages usually need a Dockerfile. Test each build on a staging branch and compare the runtime, environment and start command with what your Procfile declared on Heroku. Changing the build method is a code and config change, so include it in the scope.
How is the Heroku Postgres database restored into Coolify?
Heroku documents that pg:backups files use the pg_dump custom format. Coolify's PostgreSQL Import Backup accepts SQL dumps, custom archives, tar archives and all-database dumps, so a custom-format export can be loaded into a Coolify-managed PostgreSQL instance. The usual sequence is to take a fresh backup, restore it into a new Coolify database, run row counts and application smoke tests, then schedule the final cutover. Coolify's PostgreSQL backups also use pg_dump custom format and can upload to S3-compatible storage with retention by count, days or size, so you can configure your own recurring backups from day one. Confirm the PostgreSQL major version you deploy, since supported versions and end-of-life dates are published by the PostgreSQL project.
How do we cut over DNS safely from Heroku to Coolify?
Keep Heroku running and change DNS last. Coolify's guidance is to deploy the new app without changing production DNS, test it on a temporary domain, then point the production record at Coolify while keeping the old platform available until the new deployment is stable. Lower the record's TTL ahead of the change if your DNS provider allows it, so rollback is faster. Coolify runs a coolify-proxy container on each server, using Traefik by default or Caddy as an alternative, and both handle HTTPS automatically. Confirm certificate issuance on the new host before the switch. Remember that a rollback can redeploy a retained application image, but it does not restore databases or persistent files, so data written during the window needs its own plan.
What does Coolify Cloud add compared with self-hosting Coolify?
The self-hosted Coolify edition is Apache-2.0 licensed and Coolify's pricing page describes it as free forever with all features and no limitations or restrictions. Coolify Cloud is a hosted control plane: Coolify runs the instance on its managed infrastructure while you bring your own servers. Its pricing is $5 per month for 2 connected servers plus $3 per month for each additional server, with a 20% discount for annual billing. What you gain is not having to operate the dashboard itself. What you still own is the servers, the applications, the databases and their backups, so it does not remove the operational work described above. Ask whether the control plane's data location and support terms fit your data residency and compliance requirements before choosing it.
How DeployOpen scopes and runs a Heroku to Coolify migration
Every DeployOpen migration starts with a written scope, not an open-ended hourly engagement. Before any work begins, the scope names the Heroku apps in the move, the build path chosen for each (Nixpacks, Railpack, a Dockerfile or a prebuilt image), the PostgreSQL databases and their backup restores, the config vars to recreate, the domains to cut over, and the deliverables and timeline agreed in writing. Work is carried out on Coolify installed on servers in your own cloud account, data center or private network, which you control. Because Coolify connects to each server over SSH and needs at least 2 CPU cores, 2 GB RAM and 10 GB of free disk, the scope should also confirm which hosts receive the install, who holds SSH access, and where backups are stored. A quote follows from that written scope, so the scope is the document to request and review first.
The work beyond deployment is where most of the effort sits, and the scope should price it explicitly. That includes restoring the pg:backups dump, which Heroku documents in pg_dump custom format, into a Coolify-managed PostgreSQL through its Import Backup function, then configuring scheduled PostgreSQL backups with retention and an off-server copy, since Coolify does not restore databases or persistent files on rollback. Hardening covers the proxy choice (Traefik by default or Caddy), firewall rules, and secrets handling for the config vars, which Heroku caps at 64 KB per app and which Coolify stores in build-time, runtime and preview scopes. DeployOpen delivers the runbook, configuration records and cutover checklist as documentation your team keeps. Ongoing support, Coolify upgrades and continuous testing are available as optional retainers after the migration closes.

