Migrate from Heroku to Kubernetes

Moving Heroku apps to Kubernetes means rebuilding process types, config, add-ons and cutover on infrastructure you operate. This page sets out what maps cleanly, what needs rework and how to plan the move.

On this page

Migrate from Heroku to Kubernetes when a single-server PaaS stops fitting

Moving a Heroku application to Kubernetes is a rebuild of four things: how the code becomes an image, how each process runs, how configuration and secrets reach the workload, and where the data lives. It is not a lift of dynos onto nodes. Teams that take this path usually hand the work to a platform or DevOps group, often with an implementation partner, because the cluster, the registry, the ingress and the database each become systems the organization operates. The effort depends mostly on how many apps, add-ons and cross-service dependencies exist, and on whether the team already runs Kubernetes elsewhere. Heroku's own next-generation Fir platform is built on Kubernetes, OCI containers and OpenTelemetry, and it builds apps only with Cloud Native Buildpacks, so the build step of your current apps may translate more directly than a Dockerfile-only setup would. Heroku also announced on February 6, 2026 that it is moving to a sustaining engineering model focused on stability, security, reliability and support. Treat that as a planning input for your renewal calendar, not as a reason to move in a hurry.

The short answer on risk is that the largest exposure sits in the parts Heroku used to handle for you. A Kubernetes cluster needs control plane high availability, an etcd backup plan and a Kubernetes upgrade cadence that stays within the version skew policy, and Kubernetes Secrets are stored unencrypted in etcd by default, so encryption at rest and least-privilege RBAC must be configured before any production config moves over. Database moves carry the most consequence. A managed Heroku Postgres database becomes a PostgreSQL cluster you run, with backups, point-in-time recovery, failover tooling and major version upgrades assigned to your team. Before committing, confirm with your partner and your own environment who owns on-call, which PostgreSQL major version you will target, and how a rollback will restore data as well as code. Ask for a written scope with named deliverables for each app, add-on and cutover step, so the effort and the risk are visible before work starts.

Which Heroku capabilities map cleanly to Kubernetes and which need rework

This table maps each Heroku capability that a team usually relies on to its closest Kubernetes equivalent, and marks whether the move is clean, needs rework or leaves a gap you must fill. Read the migration note as the work you will own, then confirm each row against your own apps, add-ons and network design before you estimate effort. The main takeaway is that the application build and process model translate well, while the data services, networking and operations are where most of the new responsibility sits.

Heroku capabilityKubernetes equivalentMigration note
Buildpack buildsCloud Native Buildpacks run in a build pipeline that produces an OCI imageClean for apps on Heroku's buildpacks, since Heroku's Fir platform also builds with Cloud Native Buildpacks. Confirm each buildpack version and any custom buildpacks your apps use.
Procfile process typesSeparate Deployments, one per process type (web, worker, clock)Needs rework. You write a manifest per process, set probes, resource requests and replica counts, and decide which processes need a Service.
Release phaseKubernetes Job run before the Deployment rolls outNeeds rework. Heroku runs release commands automatically on each deploy. You must order the Job in your pipeline and handle failed migrations yourself.
Config varsKubernetes Secrets and ConfigMapsNeeds rework. Secrets are stored unencrypted in etcd by default, so enable encryption at rest and restrict list and watch access with RBAC, or use an external secrets store.
Heroku PostgresSelf-managed PostgreSQL, such as an operator, a managed database in your cloud or a server you runGap. Heroku's backups, forks and point-in-time recovery are not included. You must plan backups, failover, upgrades and connection pooling.
Heroku Data for RedisValkey or Redis deployed in the cluster or on a managed service you chooseGap. Confirm persistence, memory limits and failover settings with your team, since cache and queue data may need a different durability setting.
Heroku SchedulerKubernetes CronJobsNeeds rework. CronJobs need explicit concurrency and deadline settings, and you must add alerting for missed or failed runs.
Review AppsNo direct equivalent. Use per-branch namespaces created by your CI/CD pipelineGap. Namespace lifecycle, wildcard DNS and preview data are your work to design and automate.
Private Spaces and networkingNetwork policies, ingress controller, cluster networking and your cloud's private networkGap. Heroku's private network model does not carry over. Confirm your ingress, TLS, egress rules and network policy design with your security team.
Metrics and loggingMetrics and log pipelines you deploy, such as OpenTelemetry, Prometheus and GrafanaGap. Heroku's log drains and metrics are replaced by stacks you install, size and retain. Confirm retention and alert routing with your operations team.

How Cloud Native Buildpacks keep the Heroku build model

Cloud Native Buildpacks turn application source into OCI container images, and that is the build step Heroku's own next-generation platform now uses. Heroku's Fir platform, generally available since April 2, 2025, runs on Kubernetes and OCI containers and builds apps only with Cloud Native Buildpacks, so the buildpack model you rely on today is the same one a Kubernetes target expects. *Cloud Native Buildpacks* is a Cloud Native Computing Foundation graduated project, and Google, Heroku and the Paketo project maintain buildpacks for it. For a migration, this means the buildpack layer of your app can usually stay the same while the place it runs changes. Confirm which buildpack names and versions your apps currently pin in project.toml or the Heroku build output, because Heroku buildpack versions and the Paketo equivalents do not always match one to one.

In CI, the practical pattern is to run the pack CLI or a buildpack-aware builder against each commit, push the resulting image to a registry you control, and reference that exact image digest in your Kubernetes manifests. Each Procfile process type then becomes its own Deployment, so a web line and a worker line are two objects with separate replica counts, resource requests and health probes, not two dynos of one app. The release phase has no direct equivalent: move it to a Kubernetes Job that runs before the rollout, and treat a failed Job as a failed deploy. Next.js illustrates the same decision. Deploying it as a Node.js server or a Docker container supports all Next.js features, while a static export supports a limited set, so check which mode your front end uses before you decide whether it belongs in a container at all. Ask your registry and CI vendors to confirm how they handle buildpack caching and image signing.

What the migration sequence looks like, step by step

The sequence moves each Heroku app to Kubernetes in a controlled order, so every app has a tested image, a rollback path and an archived copy of its Heroku state before Heroku resources are removed. Each step ends with a named artifact that the next step depends on.

  1. Inventory apps, add-ons and integrations

    Your team lists every Heroku app, its Procfile process types, release phase commands, config vars, add-ons, scheduler jobs, custom domains, certificates, webhooks and third-party integrations. Record which app depends on which add-on and which external service calls it. The output is an inventory sheet that names an owner, a data classification and a target Kubernetes component for each item. The step is done when the platform owner and each app owner have signed the sheet.

  2. Pilot on one low-risk app

    Choose one internal or low-traffic app with a small data footprint and no complex add-ons. Build its container image with Cloud Native Buildpacks, write the Deployment, Service, Ingress and Job manifests, and load config vars into Kubernetes Secrets. The output is a working image, a manifest set stored in Git and a short note of every change needed to run the app. The pilot proves the toolchain before larger apps depend on it.

  3. Rehearse rollback on the pilot

    Before any production traffic moves, deploy the pilot to the cluster, then test the rollback path by redeploying the previous image tag and restoring a database copy into a separate PostgreSQL instance. Confirm that the Secrets and the database schema match what the previous release expects. The output is a tested rollback procedure with the commands written down. Do not treat rollback as complete until someone has run it end to end.

  4. Run both platforms in parallel

    Keep the Heroku app running while the Kubernetes version serves a test or internal audience. Compare logs, error rates, response times and scheduled job results between the two. For each add-on, confirm the replacement behaves the same, including connection limits, extensions and backup coverage. The output is a parity report listing every difference and whether it is accepted or fixed. Ask your team to confirm monitoring and alerting exist on the Kubernetes side before this step closes.

  5. Cut over DNS and synchronize data

    Schedule a cutover window agreed with the app owner. Put the Heroku app into read-only or maintenance mode, take a final database dump, restore it into the Kubernetes PostgreSQL, verify row counts and key queries, then lower DNS TTLs in advance and repoint the domain to the Kubernetes ingress. The output is a dated cutover runbook with named owners and a go or no-go checkpoint. Keep the Heroku app available for the rollback window written in that runbook.

  6. Decommission Heroku resources and archive exports

    After the agreed stabilization period, export the final Heroku state: Postgres backups, config var lists with secrets handled according to your policy, app metadata and build logs that your records require. Store these exports in an encrypted location you control, then remove add-ons, dynos and apps in Heroku. The output is an archived export set with a checksum list and a signed decommission record. Confirm with your procurement and legal teams how long exports must be retained.

What data and integrations to move, using documented export paths

Moving off Heroku means exporting data, reading configuration and repointing everything that calls the app. Some of these paths are documented by Heroku and others depend on your plan, so confirm each one before you set a cutover date. The cards below follow the order most teams work through: data first, then configuration, then the services that depend on both.

Heroku Postgres export

Take a heroku pg:backups capture and a separate pg_dump of the database, then restore both into PostgreSQL on the cluster. Use the pg:backups file as the restore point and a fresh pg_dump as the cutover copy. Confirm with Heroku how long backups are retained and how long download URLs stay valid, because both limits set how early you must start the transfer. Check that the target PostgreSQL major version matches the version you tested.

Config vars moved to Secrets

Read every config var with heroku config and sort the values into two groups. Non-sensitive settings go into a ConfigMap, and sensitive values such as keys and connection strings go into Secrets. Kubernetes stores Secrets unencrypted in etcd by default, so enable encryption at rest and limit list and watch access with least-privilege RBAC before you load production values. Record which values change per environment.

App inventory from the Platform API

The Heroku Platform API describes apps, formations (process types and their dyno counts), add-on attachments, domains and collaborators. Export these responses to files and use them as the inventory for Deployments, Services, Ingress records and CronJobs. Treat the inventory as a checklist rather than a guarantee of completeness, and confirm the endpoints you need against Heroku's current API reference.

Redis data as cache or rebuild

Most Heroku Data for Redis instances hold cache, session or queue data that the application can rebuild. Decide per instance whether the contents can be discarded or must be copied. If data must move, confirm with Heroku whether your plan offers an export path, then load it into Valkey or Redis on the cluster. A cache that starts empty at cutover means a cold start and a load spike on the database, so plan for it.

Add-on credentials rotated

Each add-on attaches credentials as config vars, including connection URLs for Postgres, Redis and logging services. Create new credentials in each provider after cutover, store them as Secrets and keep the Heroku-issued ones valid only until the new path is confirmed. Then revoke them, because old URLs can persist in logs, CI variables and developer machines. Use your Platform API inventory to list every attachment that needs a new credential.

Webhooks and DNS repointed

Third-party services such as Git hosts, payment processors and email providers call endpoints that point at your Heroku domain. List each webhook, its endpoint URL and its signing secret, then update them once the Kubernetes Ingress serves traffic. Lower DNS record TTLs before cutover, keep the Heroku app running until the new path is verified, and confirm the TTL values with your DNS host.

How the move differs for a single team versus a multi-team platform

A small team moving a handful of Heroku apps usually owns the whole cluster, from control plane to application manifests. The main risk is taking on infrastructure work that Heroku used to hide, so the team should decide early whether it wants a managed Kubernetes service or a self-built control plane. Kubernetes is open source under Apache 2.0, but the operator, not the license, carries the cost of running it.

  • Cluster ownership: One team holds the control plane, node pools, upgrades and on-call. Kubeadm high availability needs at least three control plane nodes and a TCP load balancer on port 6443, which is a larger footprint than a few Heroku dynos.
  • GitOps tooling: A single repository with Deployments, Services and Jobs, applied by one pipeline, is often enough. Adding a GitOps controller is optional at this size.
  • Namespaces: One namespace per environment, such as staging and production, is usually sufficient.
  • Secrets: Config vars become Kubernetes Secrets. Secrets are stored unencrypted in etcd by default, so encryption at rest must be enabled by the team.
  • Databases: Heroku Postgres is replaced by PostgreSQL the team runs, with backups and upgrades on its own schedule.

Before committing, confirm with the team who will receive pages at night and who has authority to change the cluster version.

What you take on for the cluster after cutover

The first decision after cutover is control plane topology. The kubeadm high availability guide describes a stacked control plane, where etcd runs on the same nodes as the control plane, and an external etcd cluster, where etcd runs on separate hosts. Either way you need at least three control plane nodes and a TCP load balancer in front of kube-apiserver on port 6443. Confirm with your platform team who operates the load balancer, how its health checks are configured, and whether it is highly available itself, because a single balancer reintroduces the single point of failure you moved off Heroku to avoid. etcd holds cluster state, so it needs an odd member count, and the Kubernetes documentation recommends five members in production. Plan and test etcd snapshots with etcdctl snapshot save from the start, and rehearse a restore with etcdutl, since a backup you have never restored is not yet a recovery plan.

Upgrades are recurring work you will schedule every year. Kubernetes ships roughly three minor releases a year on a cycle of about 14 weeks, and the project maintains only the three most recent minors, so an unpatched cluster falls out of support on a fixed clock. Follow the version skew policy: upgrade kube-apiserver one minor version at a time, then the controller manager, scheduler and kubelets, which may trail the API server by up to three minor versions. Budget engineering time for this cycle, and check the current support dates on the Kubernetes releases page before each planning cycle. Secrets need attention too. By default Kubernetes stores Secret objects unencrypted in etcd, so configure encryption at rest, restrict list and watch access with least-privilege RBAC, or consider an external store through the Secrets Store CSI Driver. Review the good practices for Kubernetes Secrets page before moving production credentials.

Your PostgreSQL database is the other stateful component, and it does not manage itself on Kubernetes. Supported major versions are listed by the PostgreSQL versioning policy, with version 14 supported until November 12, 2026, so confirm which major version your migrated database runs and when you must move. Minor releases can be applied by replacing executables and restarting, but major upgrades need pg_upgrade, a dump and restore, or logical replication, which can keep downtime to several seconds. PostgreSQL also does not detect a primary failure or promote a standby on its own, so you must select and operate an external failover tool, and you must test that failover path. Decide who owns backups, point-in-time recovery and restore drills, and ask whether your chosen database operator covers each of them.

What drives the cost and duration of a Heroku to Kubernetes move

This table lists the factors that change how much work and spend a Heroku to Kubernetes move involves, and how to keep each one under control. Read each row as a line item to request in a written quote, because most of the total comes from the number of apps, the data in add-ons and whether a cluster already exists. The main takeaway is that a move scoped on process types, data volume and environments is easier to price and time than one scoped on the platform as a whole.

DriverWhy it mattersHow to keep it down
Number of apps and process typesEach app needs its own image build, Deployment, Service, ingress and Job definitions for web, worker and release processes from the Procfile.Group apps that share a buildpack and base image, and retire unused process types before the move starts.
Add-on count and data sizeEach Heroku add-on needs a replacement service, and databases need a logical or dump-based migration with a cutover window.Inventory every add-on and its data volume early, and replace low-use add-ons with a single shared service where the app design allows.
Team Kubernetes experienceOperating Deployments, RBAC, Secrets and cluster upgrades takes skills that a Heroku-only team may not hold yet.Ask whether training, pairing or a runbook is included in the scope, and confirm who carries on-call after cutover.
CI pipeline changesHeroku Pipelines and Review Apps are replaced by image builds, registry pushes and deploy steps in your CI system.Reuse existing CI runners and registries where possible, and list each pipeline stage that must change in the quote.
Compliance controlsEncryption at rest for Secrets, least-privilege access, audit logging and evidence collection add design and documentation work for an assessor.Agree the control list before build starts, and confirm which controls your auditor expects to see as evidence.
Cluster build-out versus existing clustersA new production cluster with highly available control plane nodes and an etcd backup plan costs more to design and run than deploying into a cluster you already operate.Reuse a cluster your organization already supports if its security baseline fits, and confirm which items are one-time build work and which recur.
Number of environmentsEach environment such as staging, QA or preview needs its own configuration, Secrets and data handling.Limit the number of persistent environments, and confirm whether preview environments are in scope or deferred.

What usually goes wrong and how to prevent it

Most failed Heroku-to-Kubernetes moves fail on the same few assumptions: that secrets are protected, that the cluster is backed up, that add-ons come with the platform, and that a rollback restores everything. Each card below names one of these gaps and the prevention step to put in your cutover plan.

Secrets readable in etcd

Kubernetes stores Secrets unencrypted in etcd by default, so config vars moved from Heroku can sit in plain form on the control plane. Enable encryption at rest for Secrets before any production data moves, and restrict list and watch access with least-privilege RBAC. Where policy requires it, check whether an external store through the Secrets Store CSI Driver fits your environment.

etcd backups never scheduled

The cluster state lives in etcd, and a control plane without a tested etcd backup can lose every Deployment, Service and Secret definition. Schedule etcdctl snapshot save runs, store snapshots off the cluster, and practice a restore with etcdutl on a separate environment. Confirm who owns this job after handover, because it does not appear in an application deployment pipeline.

Add-ons assumed on the cluster

Heroku add-ons such as Postgres, Redis, Scheduler and log drains do not exist in a plain Kubernetes cluster. Inventory every add-on each app uses, then assign a replacement and an owner for each: a managed database, a self-run StatefulSet, a CronJob, or a log shipper. Treat missing scheduler or log routing as a launch blocker, not a later fix.

Rollbacks that skip data

Rolling back a Deployment reverts the container image and configuration, but it does not restore a database or files written since the last release. Coolify's guide for teams leaving managed platforms makes the same point about retained images. Before cutover, define which writes are reversible, take a database snapshot tied to each release, and document the restore order for any rollback.

Postgres upgrades without rehearsal

A Postgres major upgrade that has never run against a copy of production data is a common source of extended downtime. Rehearse the path you choose, whether pg_upgrade, logical replication or dump and restore, against a recent backup, and time it. Check the supported-version calendar when you pick the target major version, since an older major may leave support during your planning window.

Cutover without a return path

Switching DNS and deleting the Heroku apps on the same day removes the fallback if the new cluster misbehaves under real traffic. Keep the Heroku apps and their databases running for an agreed window, lower DNS TTLs before the change, and define the exact condition that triggers a reversal. Confirm with your provider that Heroku resources can be paused or kept at a known cost during that window.

Questions buyers ask before moving from Heroku to Kubernetes

How much effort does a Heroku to Kubernetes move usually take?

Effort depends mainly on how many apps, add-ons and integrations you run, and how much of your release process is tied to Heroku's conventions. Each app needs a container image built with Cloud Native Buildpacks, its Procfile process types turned into Deployments and Jobs, its config vars moved to Secrets, and its add-ons replaced. Before you commit, inventory every app, every add-on and every external system that calls or depends on them. No fixed effort figure is supplied for this move, so ask any implementation partner to size it from your own inventory and to show that sizing in the written scope.

How long does the migration take, and what sets the timeline?

The timeline is set by inventory size, the number of stateful services, the cluster build and your change windows, not by the Heroku migration itself. The clusters you run must be ready before any app moves, and the database cutover is the step with the most risk. Kubernetes releases come roughly three times per year, so plan an upgrade cadence into the schedule from day one. No duration is supplied for this migration, so request a phased plan with dated milestones in the written scope rather than relying on a general estimate.

Can our own team run this migration without outside help?

A team with working Kubernetes, container and database operations experience can do the move internally, but the skill gap is usually larger than teams expect. The work covers cluster design, a highly available control plane, etcd backups, Secrets encryption, RBAC, ingress and TLS, and PostgreSQL operations. Assess your staff against those areas before deciding. If you choose outside help, a fixed-scope engagement with written deliverables and a handover plan lets your team take over operations at a known point.

What does our staff need to know to run the platform afterward?

Your staff need to own the ongoing operations that Heroku previously handled for you. That includes applying Kubernetes upgrades in the required order, since the kube-apiserver must be upgraded one minor version at a time before the other control plane components and kubelets. They also need to run etcd snapshot backups, handle node patching, manage Secrets access, and monitor workloads. Ask any partner to document these runbooks and to train the people who will run them.

Can Heroku Postgres move to our own PostgreSQL without downtime?

Logical replication can reduce downtime sharply because it works between different PostgreSQL major versions. The PostgreSQL documentation describes major upgrades with only several seconds of downtime using this method, but the outcome depends on your write volume, schema, extensions and how cleanly your application handles a switchover. Plan the cutover with a rehearsal on a copy of production, and confirm with the database team which PostgreSQL version you will target. Automatic failover is not built into PostgreSQL itself, so you also need an external tool for high availability.

Do we need Kubernetes, or would Dokku or Coolify be enough?

Choose Kubernetes when you need multiple servers, scheduling across nodes, or a platform your engineers already run for other workloads. Dokku and Coolify on one or a few servers can be enough for a smaller set of apps with modest availability needs, and they are much less work to operate. Kubernetes adds control plane high availability, etcd operations and a larger upgrade surface. Decide against your actual scale, your team's skills and your recovery targets. A written comparison from your partner should state those trade-offs for your workloads.

How does Heroku's sustaining engineering shift affect our timing and what should a quote include?

Heroku announced on February 6, 2026 that it is moving to a sustaining engineering model focused on stability, security, reliability and support rather than new features, and that Enterprise Account contracts will no longer be offered to new customers. That is not a shutdown, but it means you should plan your move around your renewal dates and set your own deadline. A quote should list the written scope, the inventory assumptions, the number of environments, the database cutover approach, the training and handover, the post-go-live support model, and which items are one-time versus recurring. Ask for each line to be tied to a deliverable.

How DeployOpen scopes and runs a Heroku to Kubernetes migration

DeployOpen is a Chainscore Labs company that plans, implements, hardens, backs up, documents and supports self-hosted open-source platforms inside your own cloud accounts, data centers or air-gapped networks. For a Heroku to Kubernetes move, we start with a written scope that maps each app, process type, add-on and cutover step, then build and document the cluster and workloads in your environment.

How we scope

  • Inventory each Heroku app, its Procfile process types, release phase, scheduled jobs and add-ons before any build work starts.
  • Agree in writing which apps move, which add-ons are replaced with PostgreSQL or Valkey, and what stays out of scope.
  • Confirm with you where the cluster will run, who owns control plane operations, and which data residency and access rules apply.

How we build

  • Build container images with Cloud Native Buildpacks and translate process types into Deployments and Jobs for each app.
  • Move config vars into Kubernetes Secrets with encryption at rest configured and RBAC limited to named roles.
  • Set up the control plane, etcd backups and the reverse path to your existing DNS and TLS, then test each app in a staging namespace.

How we hand over

  • Deliver runbooks for deploys, rollbacks, etcd snapshot and restore, and Kubernetes version upgrades in your environment.
  • Document the database backup, restore and failover approach, and which steps your team owns after handover.
  • Provide the evidence and configuration records your internal or external auditors will ask for, without issuing any audit or certification.

How we support

  • Engagements are fixed-scope, with scope, deliverables and timelines agreed in writing before work starts.
  • Ongoing support, Kubernetes upgrades and continuous security testing are available as retainers after handover.
  • Ask us to confirm in the written scope how cluster upgrades, patching and on-call responsibilities will be divided between your team and ours.

Talk to our team.

Tell us what you're working on, whether it's a deployment, an audit, a security test or a cyber range. You'll speak with an engineer who can help you scope it.

  • 30-minute call: free, with no obligation.
  • NDA on request: we can sign before you share details.
  • Clear next steps: a scope and plan after the call.