Outgrowing Netlify: How to Move Your App and Backend Services to Kubernetes in Your Own Cloud Account
A step-by-step migration path from Netlify to Kubernetes running in your own AWS, GCP, Azure, or Scaleway account, covering the static frontend, serverless functions, a real managed database, environment variables, preview deployments, and DNS cutover.
The hard part of leaving Netlify is not Kubernetes. It is that you are replacing one product with six: a global CDN, automatic TLS, a build pipeline, a preview environment per pull request, a serverless runtime, and (once you need it) a real database. Most teams plan for the runtime and get surprised by the other five on cutover day.
I have watched a lot of teams do this migration, and the ones who do it well treat it as an ordered project, not a weekend rewrite. Below is the order I recommend, with the real limits and prices I could verify, and an honest answer to the question most posts skip: when you should not migrate at all.
You are splitting one product into five things you now own: static frontend hosting plus CDN, serverless functions (now long-running containers), a managed database in your own VPC, TLS and DNS, and the deploy pipeline with preview environments.
The trigger is rarely cost. It is needing a persistent database in a VPC you control, background work beyond Netlify's function timeouts, private networking to internal systems, and compliance rules that require data to stay in your own cloud account.
The lowest-risk order is fixed: inventory the Netlify project, pick the cloud and managed control plane, containerise the backend, migrate the database with logical replication, then move the frontend and flip DNS last with a 60-second TTL.
A hybrid end state is legitimate. Keep the static frontend on Netlify, move only the backend and database to Kubernetes. Many teams should stop there.
You do not have to hand-write Helm charts, Terraform, and CI pipelines. Qovery deploys your containers and provisions managed databases inside your own AWS, GCP, Azure, or Scaleway account, or your existing cluster, and restores the two Netlify behaviours teams miss most: git-push deploys and a preview environment per pull request.
When does it actually make sense to migrate off Netlify?
Migrate off Netlify when you need a persistent relational database inside a VPC you control, background or scheduled work that exceeds serverless function timeouts, private networking to internal systems, or data residency and compliance control. Do not migrate just because the bill went up, because on a small app Kubernetes will almost certainly cost you more.
Netlify is an excellent product, and I want to be fair about that before anyone rips out a working setup. Here are the good reasons to leave:
A relational database with connection pooling that lives in your own VPC, not a third-party host.
Workers, queues, or cron jobs that run longer than a serverless function is allowed to. Netlify caps synchronous functions at 60 seconds and Background Functions at 15 minutes (Netlify Functions docs, Background Functions docs). If your job needs an hour, neither fits.
Private VPC networking, VPN, or peering to internal systems.
SOC 2 or data-residency requirements that force data into a cloud account you own.
Cloud commitments or Savings Plans billed in your own name.
And the bad reasons: "Kubernetes looks more serious," chasing a marginally cheaper bill on a small app, or resume-driven architecture. If you have a static marketing site, no database, no background work, and no compliance driver, stay on Netlify. You will not win.
There is a middle path I recommend often: keep the static frontend on Netlify and move only the backend and database to Kubernetes. If your frontend is happy and your only pain is the runtime or the data layer, that hybrid is the right place to stop. Teams with a small product team and no dedicated platform engineer should seriously consider ending there.
Whatever you move, you are rebuilding things Netlify gave you for free: a global CDN and edge, atomic deploys with instant rollback, automatic TLS, and a deploy preview per pull request. Plan for all four.
Netlify capability
Equivalent on Kubernetes in your own cloud
Who operates it after migration
Static hosting + CDN
Object storage (S3 / GCS / Azure Blob / Scaleway Object Storage) behind a CDN, or an Nginx container behind Ingress
You, plus your CDN vendor
Netlify Functions
Containerised API service behind Ingress
Your team
Background Functions
Worker Deployment consuming a queue (SQS, Pub/Sub, Redis)
Cloud provider runs the engine, you run the schema
Deploy previews
Ephemeral preview environments per pull request
Your platform or a tool that provides them
Automatic TLS
cert-manager, or the cloud load balancer's managed certificate
Your team
What exactly do you have to migrate out of a Netlify project?
A Netlify project is seven things, not one: a build command and static output, a functions directory, environment variables per deploy context, netlify.toml redirects and headers, add-ons like Forms and Identity, any attached database, and DNS with TLS. Inventory all seven before you touch Kubernetes, because the ones teams forget (headers, add-ons, build contexts) are the ones that break after cutover.
Work through this list and write down the destination for each item:
Build command and output directory. Next.js, Remix, Astro, Nuxt, and SvelteKit each behave differently once you drop Netlify's framework adapter. Rebuild the output locally first and confirm it is what you expect.
netlify.toml. Redirects, rewrites, proxies, custom headers, and caching rules all live here. They become Ingress rules, CDN behaviours, or Nginx config, and the SPA fallback rule is the one people forget.
Functions directory. Map each function to an endpoint in a containerised API, a worker, or a CronJob. Put the mapping in a table before you write any code.
Environment variables and secrets per deploy context. Production, branch deploys, and deploy previews each have their own set. Decide their new home: Kubernetes Secrets, a cloud secret manager, or platform-level variables.
Add-ons with no direct Kubernetes equivalent. Netlify Forms needs a form backend. Netlify Identity needs an OIDC provider such as Auth0, Clerk, or Cognito. Netlify Analytics needs an analytics tool. Netlify Blobs needs object storage. Name a replacement category for each.
Data already outside Netlify. Supabase, Neon, PlanetScale, or MongoDB Atlas. Decide whether each comes into your VPC too, or stays where it is.
DNS and TLS. Custom domains, the DNS zone, existing certificates, and the TTL plan you will need on cutover day.
Which cloud and Kubernetes setup should you land on?
Land on the cloud where your data and compliance obligations already live, then run a managed Kubernetes control plane there: EKS, GKE, AKS, or Scaleway Kapsule. Self-managing a control plane buys a product team nothing, and the cluster is not where your differentiation budget should go.
The managed control plane is cheap relative to the compute. What "managed" does not cover is the long tail you still operate: node upgrades, the ingress controller, cert-manager, external-dns, the metrics and log pipeline, IAM, network policy, and autoscaling tuning. Budget for that work, because it does not disappear.
Managed Kubernetes
Control plane cost
Managed Postgres counterpart
Upgrade responsibility
AWS EKS
$0.10 per cluster/hour, standard support (EKS pricing)
Amazon RDS / Aurora for PostgreSQL
You trigger upgrades; AWS runs the control plane
GCP GKE
$0.10 per cluster/hour, with $74.40/month free credit per billing account (GKE pricing)
Cloud SQL for PostgreSQL
Autopilot auto-manages; Standard you manage nodes
Azure AKS
Free tier has no financially backed SLA; Standard tier adds an uptime SLA (99.95% with availability zones) for a per-cluster fee (AKS tiers)
Azure Database for PostgreSQL
You trigger upgrades
Scaleway Kapsule
Mutualised control plane is free; dedicated control planes start around €0.11/hour (Scaleway pricing)
Scaleway Managed Database for PostgreSQL
You trigger upgrades
Do not run Postgres in-cluster as your first move. You would be signing up to operate backups, failover, point-in-time recovery, and the on-call that comes with them. A managed database hands all of that to the cloud provider for a predictable fee.
If you already run a Kubernetes cluster, bring it. A bring-your-own-cluster path can shorten this migration by weeks, because you skip the control-plane and networking setup entirely.
Here is a concrete baseline so the number is checkable. A minimal production setup on AWS in us-east-1, priced with the AWS Pricing Calculator:
Component
Spec (us-east-1)
Approx. monthly
EKS control plane
1 cluster, standard support, $0.10/hr
~$73
Worker nodes
2 x t3.medium on-demand (2 vCPU / 4 GB each)
~$60
Managed Postgres
1 x db.t3.small, Single-AZ, 20 GB gp3
~$25
Load balancer
1 x Application Load Balancer ($0.0225/hr + LCU, ELB pricing)
~$18
Total
before data transfer and storage growth
~$176
That is the floor for "a small app in production," and it is more than a Netlify Free or Pro plan. Netlify's current credit-based plans start at $0/month (Free) and from $20/month (Pro) (Netlify billing docs). If cost is your only driver, this table is your answer: do not migrate.
How do you migrate Netlify Functions to containers on Kubernetes?
Move the backend first. Wrap your Netlify Functions into one or more long-running HTTP services in a container, deploy them behind an Ingress, and point the still-on-Netlify frontend at the new API URL. This clears the risky half of the migration while the frontend stays untouched, and rollback is a single environment-variable change in Netlify.
For this section I will use GCP as the illustrative target, but the pattern is identical on AWS, Azure, or Scaleway. Each function handler becomes a route in a small Express, Fastify, FastAPI, or Go service. The per-invocation bundling and the cold-start workarounds you built for serverless both disappear, and you get persistent database connections, in-process caching, and no 60-second ceiling.
The jobs that do not fit an HTTP service go elsewhere. Background Functions become a Deployment consuming a queue (Pub/Sub on GCP, SQS on AWS, or Redis anywhere). Scheduled Functions become Kubernetes CronJobs.
Four things teams forget when they first containerise:
Dockerfile build caching, so your builds stay fast.
Readiness and liveness probes, so Kubernetes knows when a pod is actually serving.
Resource requests and limits, so one noisy service does not starve the node.
Graceful shutdown on SIGTERM, so in-flight requests finish during a rolling deploy.
Two more that cause real outages: secrets move out of the Netlify UI into a secret manager or platform-level variables, one set per environment. And because the frontend now calls a different origin, you have to sort out CORS, cookie SameSite settings, and token handling before cutover, not during it.
The reason to do the backend first is reversibility. Run both backends in parallel and shift traffic endpoint by endpoint using Netlify rewrites. Every step is a one-line change you can undo.
How do you move the database into your own cloud account without downtime?
Provision the managed database in your target cloud first, replicate into it while the old one still serves traffic, then cut over writes in a short maintenance window. Logical replication for PostgreSQL and MySQL keeps that window in minutes rather than hours, and a managed migration service can run continuous replication for you: AWS DMS supports full-load plus change data capture across Postgres, MySQL, SQL Server, Oracle, and more (AWS DMS sources), and Google Database Migration Service does continuous CDC into Cloud SQL for PostgreSQL (Google DMS docs).
The order that keeps downtime near zero:
Provision the database in a private subnet.
Grant network access from the cluster (security group, VPC peering, or private IP).
Migrate the schema, then do an initial dump and restore (pg_dump/pg_restore, or mysqldump).
Start logical replication for the delta that accumulated during the dump.
Verify row counts, sequences, and constraints.
Flip the connection string.
Keep the old database read-only as a rollback target for a week.
Know what logical replication does not carry before you rely on it. PostgreSQL logical replication needs wal_level = logical on the publisher, and it does not replicate the schema or DDL, sequence objects, or large objects (PostgreSQL logical replication restrictions). You migrate the schema yourself and reset sequences by hand after cutover. These are the gotchas that bite at 2am if you discover them live.
If you are moving off a hosted Postgres like Neon, Supabase, or Netlify DB into RDS, Cloud SQL, Azure Database for PostgreSQL, or Scaleway Managed Database, check your extensions, your SSL mode, and your pooling behaviour, and accept that branching features from those hosts do not come with you.
One warning above all others. Connection limits are the single most common post-migration outage for apps coming from serverless. Serverless runtimes open a connection per invocation, and a managed instance has a hard ceiling. On RDS, PostgreSQL max_connections defaults to LEAST({DBInstanceClassMemory/9531392}, 5000) (RDS limits); on Cloud SQL it is tiered by memory, roughly 100 connections on a 3.75 GB instance (Cloud SQL flags). Put PgBouncer or a server-side pool in front, and size your pool to the instance, not to your traffic. Run a real restore test and a real load test before cutover, not after. And seed your non-production environments from anonymised snapshots rather than copying production data around.
How do you move the frontend and cut over DNS safely?
Do the frontend last and treat DNS as the only step that is genuinely hard to reverse. Build the static output, serve it from object storage plus a CDN or from a container behind Ingress, validate on a staging hostname, lower the DNS record TTL to 60 seconds at least 24 hours ahead, then switch and keep Netlify live as a rollback target for a week.
There are two valid hosting shapes, and you choose on whether you need server rendering. For this section I will use Azure as the example. Either you build static output to Azure Blob Storage behind Azure Front Door (or S3 + CloudFront, GCS + Cloud CDN, Scaleway Object Storage + Edge Services), or you run a containerised SSR app (Next.js, Remix, Nuxt) on Kubernetes. Static plus CDN is cheaper and faster for most sites; containerised SSR is for apps that truly render per request.
Translate netlify.toml into its new home: redirects and rewrites become Ingress annotations or CDN behaviours, custom headers become CDN or Nginx config, and the SPA fallback becomes a catch-all rule. For TLS, use cert-manager with Let's Encrypt in-cluster, or the cloud load balancer's managed certificate. If you test with Let's Encrypt, mind the rate limit of 50 certificates per registered domain every 7 days (Let's Encrypt rate limits); it is easy to burn through while debugging. Replace Netlify's atomic deploy and instant rollback with immutable asset hashing plus cache invalidation.
The DNS cutover checklist:
Lower the record TTL 24 to 48 hours ahead. AWS Route 53 recommends a value between 60 and 900 seconds before a change, and tells you to wait for the old TTL to expire before switching (Route 53 migration guide). On Cloudflare, the "Auto" TTL is 300 seconds by default (Cloudflare TTL docs), so set it explicitly lower first.
Pre-warm the CDN.
Switch the record, then watch your 4xx/5xx rate and p95 latency.
Keep the Netlify deploy live.
After cutover, run synthetic checks, compare Core Web Vitals against the Netlify baseline you captured beforehand, and write down a rollback trigger in advance so nobody improvises during an incident.
How do you keep deploy previews and git-push deploys after moving to Kubernetes?
The expensive part of leaving Netlify is the developer experience, not the infrastructure. Git-push deploys, a preview URL per pull request, and zero-config TLS are what your team will miss on day two, so rebuild them deliberately: either assemble Argo CD plus Helm plus GitHub Actions plus cert-manager plus external-dns yourself, or use a platform that runs inside your own cloud account and gives them back.
The DIY stack is real and maintainable, but someone owns it. That is Helm or Kustomize for packaging, Argo CD or Flux for delivery, GitHub Actions for CI, cert-manager for TLS, external-dns for records, and an ephemeral-namespace controller for previews, plus whoever is on call for all of it. For many teams that is a full platform hire, and DevOps and cloud roles are among the better-paid engineering jobs (the 2025 Stack Overflow survey puts the global median for a DevOps engineer at $87,011 and a cloud infrastructure engineer at $103,112, Stack Overflow 2025).
This is where Qovery fits, and the reason I think it is the cleanest answer for this specific migration. Qovery runs inside your own AWS, GCP, Azure, or Scaleway account (BYOC, so the cloud bill and any Savings Plans stay in your name) or on your existing Kubernetes cluster. It gives you git-push deployments, a preview environment per pull request, environment auto-stop for non-production, managed cluster upgrades, per-environment RBAC, and databases backed by the cloud's managed services. In other words, it restores deploy previews and push-to-deploy, the two Netlify behaviours teams actually mourn, without a dedicated DevOps hire and without you operating the cluster by hand.
Be fair about the alternatives, because no single tool fits everyone:
Option
Runs in your cloud account
Managed DB in your VPC
Preview env per PR
Kubernetes underneath
Who runs cluster upgrades
Best fit
Netlify (stay)
No
No
Yes (deploy previews)
No
N/A
Static sites, no DB or compliance driver
Vercel
No
No
Yes
No
N/A
Frontend-first teams staying fully managed
Render
No
Yes (Render-managed)
Yes
Hidden
Render
Managed-but-not-Netlify, small teams
Fly.io
No
Yes (Fly Postgres)
Partial
No
Fly
Edge/regional apps
Railway
No
Yes (Railway-managed)
Yes
Hidden
Railway
Fast prototyping
Porter
Yes
Yes
Yes
Yes
Shared
BYOC teams wanting a PaaS feel
Northflank
Yes (BYOC option)
Yes
Yes
Yes
Shared
BYOC teams wanting fine control
Raw EKS/GKE/AKS + Argo CD
Yes
Yes
DIY
Yes
You
Teams with an existing platform team
Qovery
Yes (BYOC) or your existing cluster
Yes (cloud-managed)
Yes
Yes
Qovery (managed upgrades)
Teams wanting Netlify-like DX on their own cloud
The honest trade-off: once you move, you own a Kubernetes cluster, and matching a frontend cloud's edge performance for static assets still takes real CDN configuration. A platform removes most of the operational cost, not all of it. Kubernetes has become the default destination for this kind of workload anyway; the 2025 CNCF survey reports that 82% of container users now run Kubernetes in production (CNCF 2026).
How do I run this migration from Claude Code or Cursor?
Install the Qovery Agent Skills once, then describe the migration in plain language to your coding agent. It reads your repository, generates the container and deployment setup, and asks you to approve each step before anything is created in your cloud account.
Four commands, one line each on what it does and what it asks you to approve:
Install globally for every compatible agent (Claude Code, Cursor, Codex, OpenCode, Gemini CLI). This only adds the skills locally and approves nothing on its own:
Add the MCP Server to Claude Code, OAuth and read-only by default, to inspect existing environments. It asks you to authorise in the browser:
claude mcp add --transport http qovery https://mcp.qovery.com/mcp --callback-port 4242
Enable write access only when you want the agent to change things, which also requires enabling 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 map to the migration steps directly: qovery-onboard connects your AWS, GCP, Azure, or Scaleway account or your existing cluster; qovery-deploy ships the containerised backend and frontend; qovery-preview recreates Netlify deploy previews per pull request; qovery-troubleshoot debugs the first failing deploy; qovery-optimize right-sizes after cutover; qovery-speedup improves build and deploy times; and qovery-terraform exports the whole setup as code.
Then you just ask in plain language: "migrate the functions in netlify/functions into a containerised API and deploy it to my GCP account with Qovery, with a managed Postgres." Full details are in the AI agent quickstart and the Claude Code integration.
FAQ
How do I migrate a Netlify-hosted app and its backend services to Kubernetes?
Do it in a fixed order: inventory the Netlify project, choose the cloud and a managed Kubernetes control plane, containerise the backend functions behind an Ingress, migrate the database with logical replication, then move the frontend and flip DNS last with a low TTL. Keep Netlify live as a rollback target at every stage. The backend-first order means the risky work is reversible with a single environment-variable change.
What replaces Netlify Functions, Background Functions, and Edge Functions on Kubernetes?
Netlify Functions become routes in a long-running containerised API behind an Ingress. Background Functions become a worker Deployment that consumes a queue such as SQS, Pub/Sub, or Redis. Scheduled Functions become Kubernetes CronJobs, and Edge Functions become CDN edge compute or a regional Ingress. The big change is the execution model: persistent connections and no cold starts, but no automatic per-request scaling to zero.
Can I keep a deploy preview per pull request after leaving Netlify?
Yes. You can build it yourself with an ephemeral-namespace controller plus Argo CD, cert-manager, and external-dns, or use a platform like Qovery that provisions a preview environment per pull request inside your own cloud account. Preview environments are the Netlify feature teams miss most, so rebuild them deliberately rather than assuming they come for free.
How do I move my database into my own AWS, GCP, Azure, or Scaleway account without downtime?
Provision the managed database first, replicate into it with logical replication while the old database still serves traffic, verify row counts and sequences, then cut over writes in a short maintenance window. A managed service like AWS DMS or Google Database Migration Service can run continuous change data capture so the window stays in minutes. Watch connection limits closely and put a pooler like PgBouncer in front before you cut over.
Is Kubernetes cheaper than Netlify for a production app?
Usually not, for a small app. A minimal AWS setup (EKS control plane, two t3.medium nodes, one db.t3.small Postgres, one load balancer) lands around $176/month before storage and egress, which is more than Netlify's Free or Pro plans. You migrate for control, compliance, and capability, not to save money on a small footprint.
Do I need a DevOps engineer to run Kubernetes after migrating off Netlify?
Not necessarily. Raw EKS, GKE, or AKS with Argo CD realistically needs someone who owns the platform, and those roles are expensive to hire. A managed platform that runs in your own account, handles cluster upgrades, and gives you git-push deploys and preview environments lets a product team operate without a dedicated platform hire.
Can I keep the frontend on Netlify and move only the backend?
Yes, and for many teams this hybrid is the right stopping point. Keep the static frontend and CDN on Netlify, move only the backend services and the database to Kubernetes in your own cloud, and point the Netlify frontend at the new API URL. You get the database and runtime control you needed without rebuilding the CDN, TLS, and preview-environment layer Netlify already does well.
The lesson I keep coming back to: the migration fails when teams plan for the runtime and forget the other five products. Plan for all six, do them in order, and keep Netlify live until the new setup has proven itself.
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.