Webinar · Oct 20: The migration takes 2 weeks. Deciding to do it takes 6 months.

How to Migrate from DigitalOcean App Platform to Kubernetes Without Rebuilding Your Deployment Pipeline

A step-by-step path from DigitalOcean App Platform to Kubernetes (DOKS, EKS, GKE, AKS, or your own cluster) that keeps your existing git-push workflow, preview environments, and CI intact - plus a fair comparison of Kustomize, Argo CD, Backstage, Humanitec, Port, and Qovery.

Romaric Philogene
CEO & Co-founder
OCT 17, 2026 · 6 MIN
How to Migrate from DigitalOcean App Platform to Kubernetes Without Rebuilding Your Deployment Pipeline

App Platform quietly did four jobs for you: it built your code into a container, routed traffic to it, scaled it, and showed you logs and metrics. The migration to Kubernetes only feels hard because most teams try to replace all four in the same week, on top of a cluster they just stood up. Do that and it turns into a quarter-long project with a risky cutover at the end.

It does not have to go that way. The part everyone fears, your deployment pipeline, is the part that barely changes. I have run these cluster migrations, and the pipeline is almost never what breaks. Below is the path that keeps your git-push workflow, your CI, and your preview environments intact while you move the one thing that is actually App Platform specific.

Qovery · Agentic Infrastructure Platform
Kubernetes, operated through one governed API
Learn more

Key points

  • You do not have to rebuild your pipeline. A deployment pipeline has four parts - source trigger, build, registry push, and deploy - and only the last one is App Platform specific. Keep your GitHub Actions, GitLab CI, or CircleCI exactly as is and swap a single step.
  • Your App Platform spec is the migration map. Export it with doctl apps spec get <app-id> > app.yaml, then translate each component: a service becomes a Deployment plus Service plus Ingress, a worker becomes a Deployment with no Service, a job becomes a Job or CronJob, an encrypted env var becomes a Secret, and a managed database stays exactly where it is.
  • There are three realistic landing zones. Raw manifests with Kustomize plus Argo CD (most control, most ongoing ops), a self-assembled portal on Backstage (most assembly, needs a platform team), or an internal developer platform like Qovery, Humanitec, or Port that recreates App Platform's git-push and per-PR preview experience on Kubernetes you own.
  • Migrate in slices, never in one cutover. Stateless services first, managed databases untouched, both platforms running in parallel behind DNS weighting for at least one business cycle, then workers and cron jobs, then decommission. Budget 2 to 6 weeks for a typical 5 to 15 service app.
  • "No rebuild" is honest about the pipeline, not about new infrastructure. You now own a cluster, an ingress controller, certificate renewal, and an observability stack. That ownership, not the CI change, is where the weeks go.

Can you move from DigitalOcean App Platform to Kubernetes without rebuilding your deployment pipeline?

Yes. Your pipeline is already mostly portable, because App Platform's build step produces a container image and so does your CI. A deployment pipeline has four real parts - source trigger, build, artifact push, and deploy and rollout - and only the deploy step is App Platform specific. That is the only step you replace.

Walk through the four parts and name what survives untouched:

  • Source trigger: your branch and tag rules, test jobs, and required checks stay identical.
  • Build: your image tags and build logic stay identical.
  • Artifact push: your registry and registry credentials stay identical.
  • Deploy: this is the only App Platform specific step, and the only one you change.

Your rollback habit survives too. If your mental model of rollback is "redeploy a previous image tag," that works the same way on Kubernetes.

The build is portable either way. If you already build with a Dockerfile on App Platform, your image runs on Kubernetes with zero changes. If you rely on Cloud Native Buildpacks, App Platform auto-detects languages like Python, Go, Node.js, Ruby, Rust, and Bun (DigitalOcean buildpack reference), and you keep buildpacks by running the pack CLI in CI or by letting an internal developer platform run them for you. You do not have to hand-write Dockerfiles as a prerequisite.

Here is the honest part. "No rebuild" means no CI rewrite and no change to how developers ship. It does not mean zero new infrastructure. App Platform was quietly giving you automatic HTTPS and managed certificates, a per-app routing layer, built-in logs and metrics, a single autoscaling slider, and per-PR preview deploys. Those you now own. The pipeline change is usually a day of work per service. The cluster, ingress, secrets, and observability around it are where the weeks go.

What does each DigitalOcean App Platform concept map to in Kubernetes?

Every App Platform primitive has a direct Kubernetes equivalent, so this is a translation exercise and not a redesign. Export the spec first with doctl apps spec get <app-id> > app.yaml. It holds your env vars, routes, health checks, instance sizes, and scaling rules, which are exactly the inputs the Kubernetes objects need.

App Platform conceptKubernetes equivalentWho provides it
Web serviceDeployment + Service + IngressYou (manifests) or an IDP
WorkerDeployment, no ServiceYou or an IDP
Pre/post-deploy jobJob + init container, or sync hooksYou or an IDP
Cron-style jobCronJobYou or an IDP
Static siteObject storage + CDN, or an Nginx DeploymentYou or a cloud service
Internal serviceService of type ClusterIPYou or an IDP
Env varsConfigMapYou or an IDP
Encrypted env varsSecret (encrypted at rest)You + External Secrets / Sealed Secrets
Bindable variables (${db.DATABASE_URL})Explicit Secret / ConfigMap you populateYou or an IDP
Managed databaseStays managed, unchangedYour cloud provider
Automatic TLS + domainscert-manager + ingress controllerA controller you install
AutoscalingHPA + KEDA + node autoscalerControllers you install
Build (buildpack or Dockerfile)Your CI, or an IDP that runs buildpacksYou or an IDP
Container registryAny OCI registry (DOCR, ECR, GHCR)A cloud service
Logs / metricsPrometheus + Grafana, or a vendorYou or a vendor
Rollbackkubectl rollout undo / revision historyKubernetes or an IDP
Instance sizeResource requests and limitsYou (write them down now)

Three rows trip teams up, so call them out:

  • Automatic TLS becomes cert-manager plus an ingress controller. App Platform renewed certificates silently; now a controller does, and you watch it.
  • Built-in build and registry become your CI plus a container registry you choose.
  • Bindable variable interpolation like ${db.DATABASE_URL} becomes explicit Secrets and ConfigMaps you populate yourself. Nothing fills them in automatically.

Two rules keep this safe. First, keep managed databases managed. DigitalOcean Managed Postgres, MySQL, and Valkey stay exactly where they are. Moving stateful data into the cluster during a migration is a separate project with its own risk profile, and mixing it into the cutover is how teams lose data. Second, write down the App Platform instance size for every component before you touch anything, because Kubernetes will not size containers for you. Pre-deploy and post-deploy jobs also need care: App Platform guarantees a pre-deploy job finishes before rollout, and you reproduce that ordering explicitly with init containers or sync hooks.

Which Kubernetes cluster should you land on - DOKS, EKS, GKE, AKS, or your own?

DigitalOcean Kubernetes (DOKS) is the lowest-friction landing zone because your VPC, managed databases, Spaces, load balancers, and container registry stay exactly where they are. The migration steps are identical if you are leaving DigitalOcean for AWS, GCP, Azure, Scaleway, or a cluster you already run. Only a data migration and a registry move get added.

Landing zoneControl plane costDO databases reachable without data migration?Registry change?Node pricing referenceTypical fit
DOKSFree, HA +$40/moYes, same VPCNo, DOCR worksFrom $12/mo per nodeStaying on DO, want control
EKSPaid per cluster/hourNo, migrate dataYes, to ECRAWS EC2 ratesAlready on or moving to AWS
GKEFree tier + paid tiersNo, migrate dataYes, to Artifact RegistryGCE ratesAlready on or moving to GCP
AKSFree (paid SLA tier)No, migrate dataYes, to ACRAzure VM ratesAlready on or moving to Azure
Scaleway KapsuleFree (paid HA tier)No, migrate dataYesScaleway instance ratesEU data residency, cost
Existing / self-managedYour hardwareDepends on networkMaybeYour ownYou already run Kubernetes

On DigitalOcean, the DOKS control plane is free, high availability adds $40/month, worker nodes start around $12/month, and a load balancer to back your ingress starts at $12/month (DOKS pricing, Load Balancer pricing). App Platform moved to modular instance pricing, with a shared 1 vCPU / 512 MiB container at $5/month and 1 vCPU / 1 GiB at $10/month (App Platform pricing). Pull current numbers yourself before you commit, since both pages change.

The savings do not come from Kubernetes being cheap. They come from bin-packing: three separate 1 GB App Platform containers each billed on their own can share one larger node. That only works if you set resource requests honestly, and it comes with a sizing tax. You never get 100% of a node for your pods, because the kubelet and OS reserve CPU and memory first. Allocatable capacity is Capacity - kubeReserved - systemReserved - evictionThreshold (Kubernetes reserve-compute-resources docs), so budget for the overhead when you size node pools.

One factual note on Qovery for this choice: Qovery provisions and operates Kubernetes inside your own AWS, GCP, Azure, or Scaleway account, and it connects to an existing cluster, DOKS included, as a bring-your-own-Kubernetes target (Qovery BYOK docs). More on where that fits in the tooling section.

Ship faster on infrastructure you control.
Qovery gives your team self-service deployments on your own AWS, GCP, Azure, or Scaleway account - or your existing Kubernetes cluster. Start deploying in under 10 minutes.

What is the step-by-step migration plan that keeps developers shipping the same way?

Run it as eight steps in slices, with both platforms live until the end. The sequence matters more than any single step.

  1. Export the source of truth. Run doctl apps list to get the app ID, then doctl apps spec get <app-id> > app.yaml. The default output is YAML, and you can force it with --format yaml (doctl apps spec get reference). This file is your migration map.
  2. Make CI the only thing that builds images. Your pipeline, not App Platform, builds and pushes to a registry. If you used buildpacks, decide now between pack in CI or an IDP that runs buildpacks for you.
  3. Stand up cluster, ingress, and TLS. Install an ingress controller (ingress-nginx or your cloud's own), cert-manager for certificates, and external-dns if you want DNS records automated. Check cert-manager against Let's Encrypt limits before you issue dozens of certs at once (see below).
  4. Translate one low-risk stateless service. Write its Deployment, Service, Ingress, and Secret. Take resource requests and limits from the App Platform instance size you wrote down, and derive readiness, liveness, and startup probes from the App Platform health check block.
  5. Move secrets once, properly. App Platform encrypted env vars go to Kubernetes Secrets backed by External Secrets Operator, Sealed Secrets, or an IDP secret store. Never commit plaintext secrets to git. This is where Kustomize-only setups get painful fast.
  6. Swap the deploy step only. Replace the App Platform deploy action with kubectl apply, helm upgrade, argocd app sync, or an IDP deploy call, inside the same CI job you already have. Nothing else in the pipeline moves.
  7. Run both platforms in parallel and shift traffic slowly. Keep the App Platform app live, move a slice of traffic with DNS weighting or a CDN, and compare error rate and p95 latency for at least a week before going further.
  8. Move workers and cron jobs last, then decommission. Managed databases stay untouched from step 1 to step 8.

The rollback plan is the same at every step: the App Platform app remains fully deployable until DNS has been moved for one complete business cycle. If anything looks wrong, you shift weight back and you have lost nothing.

How do you keep preview environments, autoscaling, and rollbacks after leaving App Platform?

Each of these three has a concrete Kubernetes replacement, and each is now a system your team owns. That ownership is the real cost of the migration, so plan for it explicitly.

  • Per-PR preview environments. Argo CD ApplicationSets with the pull request generator can create an app per PR, or an IDP can spin up a full environment per PR including its dependent databases and tear it down on merge. Qovery does the latter natively with per-PR preview environments.
  • Autoscaling. App Platform's single slider becomes three separate layers you configure and monitor: HPA on CPU or memory, KEDA for queue depth and event-driven scaling, and Cluster Autoscaler or Karpenter for nodes. Say it plainly to your team: that is three things to watch, not one.
  • Rollbacks. Use kubectl rollout undo against Deployment revision history, Argo CD's history and rollback, or an IDP's one-click redeploy of a previous image. Keep immutable image tags so a rollback is deterministic.

The cost surprise that bites every team: non-production environments running 24/7 on nodes you pay for. App Platform billed per container, so an idle preview was cheap. A cluster bills for capacity whether you use it or not, and the Cast AI 2026 benchmark found average CPU utilization at just 8% and memory at 20%, with CPU over-provisioning at 69% (Cast AI 2026 report). Environment auto-stop for non-prod and honest requests and limits are what keep your bill from exploding. Observability is the other line item teams forget: App Platform's built-in logs and metrics become your own stack, Prometheus plus Grafana or a vendor, and that costs both money and engineer-hours. Budget it before the first incident, not after.

Kustomize, Argo CD, Backstage, Humanitec, Port, or Qovery - which should replace App Platform?

Choose by how much platform work your team wants to own. Kustomize plus Argo CD gives maximum control and maximum permanent ownership. Backstage, Humanitec, and Port assume you already have a platform team and a running cluster. Qovery is the shortest path for teams who want App Platform's developer experience back on Kubernetes in their own cloud account without hiring a dedicated DevOps engineer, which matters when US total compensation for that role sits around $150K (levels.fyi DevOps Engineer).

ToolWhat it actually isOperates the cluster?Replaces git-push flow?Per-PR previews OOTB?Who maintains itPricing model
Kustomize (+Argo CD / Flux)Manifest overlays + GitOps controllerNoPartially, you wire CIVia ApplicationSets, you build itYour platform teamFree, self-hosted
HelmPackage manager for manifestsNoNoNoYour platform teamFree
BackstageDeveloper portal / catalogNoNo, it scaffoldsNo, via pluginsDedicated maintainerFree, self-hosted
HumanitecPlatform orchestratorVia your infraYes, you model itYes, configuredYour platform teamCommercial
PortDeveloper portal + actionsNo, orchestrates yoursVia actions you buildVia actionsYour platform teamCommercial
QoveryIDP that provisions + operates K8sYes, in your accountYes, nativeYes, nativeQovery + youFree tier + commercial

Let me be fair, because credibility depends on it:

  • Argo CD and Flux are excellent, free, CNCF-graduated projects, and they are the right answer if your team already lives in YAML. Argo graduated in CNCF in December 2022 (CNCF Argo graduation), and GitOps adoption is mainstream, with the CNCF survey reporting 80% of organizations running Kubernetes in production and 77% adopting GitOps (CNCF 2024 survey). If you want to own the whole GitOps chain yourself, use Argo CD plus Kustomize and do not add a layer on top. I mean that.
  • Backstage is a developer portal, not a deployment engine. It catalogs and scaffolds services; it does not roll out your Deployment. It needs plugins and a dedicated maintainer, so treat it as a portal you pair with a deployer, not a replacement for App Platform's git-push.
  • Humanitec and Port fit large platform-engineering organizations that already have Kubernetes expertise and want to model and standardize golden paths across many teams.

Where Qovery genuinely differs: it provisions and operates Kubernetes inside your own cloud account, so the cloud bill and any committed-use discounts stay in your name. You get git-push deployments, per-PR preview environments, environment auto-stop, managed cluster upgrades, per-environment RBAC, and databases backed by managed cloud services, on AWS, GCP, Azure, Scaleway, or an existing cluster such as DOKS. It is not a hobby git-push tool, and it is not the answer for everyone. These tools also combine: plenty of teams run Argo CD for infrastructure add-ons and an IDP for application delivery, and that is a legitimate end state, not a compromise.

What usually goes wrong in a DigitalOcean App Platform to Kubernetes migration?

The pipeline is rarely what breaks. The failures cluster in five predictable places, and four of them are configuration, not architecture.

  • Missing resource requests and limits. App Platform sized containers for you; Kubernetes will not. Under-request and you get evictions and noisy neighbors; over-request and you destroy the cost case the migration was supposed to make, which is exactly how clusters end up at 8% CPU utilization (Cast AI 2026 report).
  • Aggressive liveness probes. App Platform's single HTTP check becomes readiness, liveness, and startup probes. A liveness probe that fires too early restarts pods precisely when the app is slow under load, which is the worst possible moment. Use a startup probe for slow boots and keep liveness conservative.
  • Database connectivity. Trusted sources on DigitalOcean Managed Databases must be updated to allow the cluster or its VPC, and connection pooling with PgBouncer matters far more once pod counts scale up and down.
  • Secrets sprawl. Plaintext values in Kustomize overlays are the single most common security regression in these migrations. Use Sealed Secrets, External Secrets Operator, or an IDP secret store from day one.
  • Ingress and TLS cutover. Let's Encrypt allows up to 50 certificates per registered domain per week and 5 duplicate certificates per identical set per week (Let's Encrypt rate limits). If you issue dozens of certs on switch day without pre-issuing and lowering DNS TTLs in advance, you will hit a wall at the worst time.

The failure that outlives the migration is organizational, not technical: a clean cutover with nobody assigned to upgrades. Kubernetes ships new minor releases a few times a year and supports each one for roughly a year (Kubernetes releases), which means two to three upgrades a year that you now own, plus CVE patching and add-on compatibility. Assign that ownership before cutover, or a managed option that handles upgrades for you starts to look a lot more appealing.

How do I run this migration with Claude Code, Cursor, or another coding agent?

You can hand most of this migration to a coding agent. Install the Qovery Agent Skills once, then ask your agent in plain language to deploy the services from your App Platform spec into your own cloud account, and approve each action it proposes.

  • Install the skills globally for any compatible agent (Claude Code, Cursor, Codex, OpenCode, Gemini CLI): curl -fsSL https://skill.qovery.com/install.sh | bash. One install covers every compatible agent.
  • Install project-scoped instead: curl -fsSL https://skill.qovery.com/install.sh | bash -s -- --project keeps the skills inside this repository only.
  • Add the MCP Server for Claude Code, OAuth, read-only by default: claude mcp add --transport http qovery https://mcp.qovery.com/mcp --callback-port 4242. This lets the agent inspect existing environments without changing anything.
  • Enable write access when you want the agent to act, which also requires turning on write access in the Qovery Console: claude mcp add --transport http qovery "https://mcp.qovery.com/mcp?read_write=true" --callback-port 4242.

The skills cover qovery-onboard, qovery-deploy, qovery-troubleshoot, qovery-optimize, qovery-speedup, qovery-preview, and qovery-terraform. Skills deploy; the MCP Server operates what already exists. Then just ask: "take the services in this DigitalOcean app spec and deploy them to my own AWS account with Qovery." The agent proposes a plan and asks you to approve each step. See the AI agent quickstart and the Claude Code integration.

Frequently asked questions
How do I export my DigitalOcean App Platform configuration before migrating?

Run doctl apps list to find your app ID, then doctl apps spec get <app-id> > app.yaml. The command returns the full spec as YAML by default, and you can force the format with --format yaml or --format json (doctl reference). That file contains your env vars, routes, health checks, instance sizes, and scaling rules, which are the exact inputs you translate into Kubernetes objects.

Do I have to rewrite my GitHub Actions or GitLab CI pipeline to deploy to Kubernetes?

No. A pipeline has four parts and only the deploy step is App Platform specific. Your triggers, test jobs, build, and image push stay as they are. You replace the App Platform deploy action with kubectl apply, helm upgrade, argocd app sync, or an IDP deploy call inside the same CI job. That is usually a day of work per service.

Should I migrate my DigitalOcean managed database into the Kubernetes cluster?

No, not during this migration. Keep DigitalOcean Managed Postgres, MySQL, or Valkey exactly where they are and point the cluster at them. Moving stateful data into the cluster is a separate project with its own backup, failover, and data-loss risk, and bundling it into the cutover is how teams lose data. Update the database's trusted sources to allow the cluster or its VPC and leave the data alone.

Is DigitalOcean Kubernetes (DOKS) cheaper than App Platform?

It can be, but only through bin-packing. The DOKS control plane is free, HA adds $40/month, and nodes start around $12/month (DOKS pricing), while App Platform containers start at $5 to $10/month (App Platform pricing). The savings come from running several containers on one larger node, which only pays off if you set resource requests honestly and avoid the 69% over-provisioning that is average across clusters (Cast AI 2026).

How long does a DigitalOcean App Platform to Kubernetes migration take?

Budget 2 to 6 weeks for a typical app of 5 to 15 services. The pipeline change is about a day per service. The weeks go into standing up the cluster, ingress, TLS, secrets, and observability, and into running both platforms in parallel for at least one business cycle before you decommission App Platform.

Can I get preview environments per pull request after leaving App Platform?

Yes. Argo CD ApplicationSets with the pull request generator can create an app per PR, or an internal developer platform can create and destroy a full environment per PR, including dependent databases. Qovery does this natively with per-PR preview environments and tears them down on merge, so you keep the App Platform preview experience without building it yourself. Migrating off App Platform is a chance to put your team on infrastructure it actually controls, without giving up the git-push workflow developers already like. Keep the pipeline, move the deploy step, and decide how much of the cluster you want to own.

Romaric Philogene
About the author
Romaric Philogene

Romaric founded Qovery to make Kubernetes accessible to every engineering team. He writes about platform strategy, developer experience, and the future of cloud infrastructure.

Next step

Ship faster on infrastructure you control.

Qovery gives your team self-service deployments on your own AWS, GCP, Azure, or Scaleway account - or your existing Kubernetes cluster. Start deploying in under 10 minutes.