How to Migrate from AWS App Runner to EKS Before You Hit Its Limits
AWS App Runner is the fastest way to ship a container on AWS until you hit its quotas, VPC, GPU, and sidecar limits. Here are the exact ceilings, the signals it is time to move to EKS, and a five-phase migration path that does not stall your roadmap.
AWS App Runner trades control for simplicity. No sidecars, no DaemonSets, no GPUs, no custom schedulers, no service mesh, and a hard cap of 4 vCPU and 12 GB per service (App Runner pricing). Amazon EKS removes those ceilings and hands you cluster operations in return.
There is now a sixth reason to plan a move: AWS closed App Runner to new customers. Existing customers keep running, but AWS has said it does not plan to introduce new features (App Runner availability change). If you are already on it, you are now on a service in maintenance mode.
Five technical signals mean you have outgrown App Runner: you need more than the 4 vCPU / 12 GB ceiling, you need sidecars or multi-container pods, you need GPU or batch workloads, you need cross-service traffic policy like mTLS or canaries, or your per-request concurrency model is forcing you to over-provision.
Cost flips at sustained load. App Runner bills provisioned plus active compute per service; Amazon EKS charges a flat $0.10 per cluster per hour plus the nodes you run (EKS pricing), so a steadily busy fleet usually gets cheaper on EKS while bursty, idle-heavy services stay cheaper on App Runner or ECS.
Migrate in five phases, not one weekend: inventory and a parity matrix, containerize for Kubernetes semantics, stand up EKS with IRSA or Pod Identity and ALB ingress, shift traffic per service with weighted DNS, then decommission.
The real cost of EKS is the platform team around it, not the control plane. Qovery runs that platform layer inside your own AWS account - and equally on GCP, Azure, Scaleway, or an existing Kubernetes cluster - so you keep App Runner-style git-push deploys on top of real Kubernetes.
I like AWS App Runner. For a request-response HTTP service that fits in a single container, it is one of the fastest ways to get something running on AWS without touching a cluster. The problem is not that App Runner is bad. The problem is that it is deliberately narrow, and if your product keeps growing, you will eventually push on a wall that was there by design.
Two things changed the calculus this year. First, AWS closed App Runner to new customers and stated it does not plan to ship new features for it. Existing services keep running, but you are now standing on a platform that will not grow with you. Second, the limits that used to be an occasional annoyance are the kind of thing a compliance or platform team now plans around from day one.
This is a practitioner guide for the team that is already on App Runner, likes it, and is bumping into the ceiling. I will walk through the published limits with links, the five signals it is time to move, the real cost comparison with assumptions stated out loud, a five-phase migration runbook, what actually breaks during the cutover, and only at the end, how to keep the git-push experience once you are on Amazon EKS. All pricing and quota numbers here were checked in October 2026, and both change, so verify against the linked AWS pages before you budget.
What are the actual limits of AWS App Runner?
App Runner caps you in four concrete places: compute size per service, the container model, networking and protocol support, and account-level quotas. Every one of them is a published number, so check your workload against the quota page before you architect around a guess.
The compute ceiling is the one teams hit first. App Runner supports a fixed set of CPU and memory pairings, and the largest is 4 vCPU with up to 12 GB of memory per service (App Runner pricing). There is no larger tier. If a single service needs more than that, your only option on App Runner is to shard the service, which is architecture work you probably did not plan.
The container model is the second wall. App Runner runs a single container per service. There are no sidecars, no init containers, and no DaemonSets. That rules out the entire category of sidecar-based tooling: an Envoy or Linkerd data-plane proxy, an OpenTelemetry Collector co-located with the app, a Vault agent, or a database connection proxy. Many APM agents that expect a sidecar simply cannot run.
Networking is HTTP and HTTPS, request-driven. To reach private resources in your VPC - a database, an internal API, a cache - you attach a VPC connector, and you get 10 of those per Region by default. There is no GPU or accelerator support, no built-in cron or batch primitive, and no StatefulSet equivalent for sticky identity or per-pod persistent volumes.
Autoscaling is concurrency-based. You set a max concurrency (requests per instance), a minimum size, and a maximum size, and App Runner scales instances between those bounds (App Runner auto scaling). You pay for the memory of all provisioned instances and the CPU of only the active subset. That model is a good fit for a stateless API. It is awkward for long-lived connections, queue consumers, and CPU-bound jobs that are not shaped like a web request.
Finally, the account quotas. The defaults are modest, and several are adjustable, but you should know them before you design around App Runner (App Runner service quotas):
App Runner is excellent at the thing it does. The limits are a design choice, not a defect. The question is whether your workload still fits inside them.
How do I know it is time to move from App Runner to EKS?
Move when a product requirement, not a preference, collides with a published App Runner limit and the workaround costs more than running a cluster. There are five reliable triggers, plus a new one that applies to everyone on the service.
Trigger 0 - the service is in maintenance mode. AWS closed App Runner to new customers and said it does not plan new features (availability change). This does not mean you need to leave tomorrow. It does mean you should stop building new product assumptions on top of it and have a destination picked before a limit forces your hand.
Trigger 1 - compute ceiling. A single service needs more than 4 vCPU or 12 GB, and sharding it is work you did not budget.
Trigger 2 - sidecars. You need Envoy, an OpenTelemetry Collector, a Vault agent, or a database proxy running next to the app. App Runner's single-container model has no room for it.
Trigger 3 - workload shape. GPU inference, Spark or batch, cron jobs, or queue consumers. Anything that is not a request-driven HTTP service is a poor fit for concurrency-based autoscaling.
Trigger 4 - traffic policy between services. mTLS, retries, circuit breaking, canary and blue-green at the mesh or ingress layer, or multi-Region failover. App Runner gives you none of that control.
Trigger 5 - economics at sustained load. Provisioned plus active compute across many always-on services starts to exceed a right-sized node group with bin-packed pods. More on the exact crossover below.
Be honest about the anti-triggers too. If you run low-traffic internal tools, spiky side services, or you are an early-stage team with no one to own a cluster, do not buy EKS to prove a point. Stay on App Runner while it still serves you, and when you do move, remember that Amazon ECS on Fargate and Google Cloud Run are legitimate intermediate steps that keep most of the simplicity. AWS itself now points App Runner users toward ECS Express Mode as the closest replacement.
Quick decision checklist, answerable in under a minute. If you say yes to any one of these, start planning a move:
Does a single service need more than 4 vCPU or 12 GB?
Do you need a sidecar (mesh proxy, collector, agent, DB proxy)?
Do you run GPU, batch, cron, or queue-consumer workloads?
Do you need mTLS, canary, or multi-Region traffic policy?
Are most of your services busy most of the day?
Is EKS cheaper than App Runner, and at what point does it flip?
Amazon EKS gets cheaper than App Runner once your services are busy most of the day, because App Runner bills per-service provisioned and active compute while EKS charges one flat $0.10 per cluster per hour plus nodes you can bin-pack, right-size, and buy on Spot. Below roughly a handful of mostly-idle services, App Runner usually wins.
Here are the current published rates (US East, N. Virginia, checked October 2026):
App Runner: provisioned instances at $0.007 per GB-hour, active instances at $0.064 per vCPU-hour plus $0.007 per GB-hour (App Runner pricing).
Amazon EKS: $0.10 per cluster per hour for the control plane on standard support, plus $0.50 per cluster per hour extra if you fall into extended support. You also pay for EC2 or Fargate compute on top.
Now two worked scenarios. Treat these as illustrations with explicit assumptions, not a verdict for your account.
Scenario A - 8 services, mostly idle. Each service runs 1 vCPU / 2 GB, sits at the minimum one instance to avoid cold starts, and is actively serving maybe 10% of the day. You pay provisioned memory around the clock on all eight, plus a little active compute. That is roughly a few tens of dollars per service per month, and crucially there is no base cluster fee. Standing up an EKS cluster here means paying $0.10/hour (about $73/month) for the control plane before a single pod runs, plus at least a couple of small nodes, plus the networking line items below. App Runner wins this one comfortably.
Scenario B - 25 services, busy 60 to 80% of the day. On App Runner you are now paying active compute (the $0.064 per vCPU-hour rate) for most of the day across 25 services, and it adds up fast. On EKS, you bin-pack those 25 workloads onto a right-sized node group, so you are buying raw EC2 capacity once and sharing it, amortizing the single $73/month control-plane fee across all 25 services. With Graviton nodes (AWS states up to 20% lower cost than comparable x86) and Spot capacity (up to 90% off On-Demand) for the stateless tier, the gap widens further. This is where EKS pulls ahead.
The honest part is the line items people forget. On the EKS side, budget for:
NAT Gateway: $0.045 per hour plus $0.045 per GB processed (VPC pricing). This surprises people.
Application Load Balancer: $0.0225 per hour plus $0.008 per LCU-hour (ELB pricing).
EBS volumes, cross-AZ data transfer, and log and metric storage.
Engineer time for upgrades, which is the real tiebreaker.
On the App Runner side, do not forget the minimum instance floors you pay to avoid cold starts, the observability agents you cannot co-locate as sidecars (so you ship logs another way), and VPC connector overhead.
Dimension
AWS App Runner
Amazon EKS (EC2 nodes)
EKS with Fargate
Notes
Pricing unit
Per-service provisioned + active compute
$0.10/cluster/hr + EC2 nodes
$0.10/cluster/hr + per-pod vCPU/GB
EKS base fee is fixed per cluster
Base / control-plane fee
None
$0.10/hr (~$73/mo)
$0.10/hr (~$73/mo)
+$0.50/hr in extended support
Scale to near-zero
Yes (min 1 instance)
Needs Karpenter/autoscaler
Per-pod, no idle nodes
App Runner simplest here
Spot / Graviton eligible
No
Yes
Graviton yes, Spot limited
Big EKS savings lever
Savings Plans eligible
No
Yes (EC2/Compute)
Yes (Fargate)
Locks in discounts
Bin-packing across services
No (one container/service)
Yes
No (per-pod billing)
EKS wins at density
Hidden networking costs
VPC connector
NAT + ALB + cross-AZ
NAT + ALB + cross-AZ
Budget these upfront
Upgrade responsibility
AWS
You
You (less node work)
Day-2 cost
Time to first deploy
Minutes
Days to weeks
Days
Platform layer closes this
Team skill required
Low
Kubernetes + ops
Kubernetes
Headcount is the real cost
The trade-off in one line: EKS converts variable per-service spend into fixed platform spend plus headcount. The honest comparison always includes the people cost, which is why so many teams stay on App Runner past the point where raw compute math says to leave.
Get EKS power with App Runner simplicity.
Qovery installs into your own AWS account and turns EKS into a git-push platform: preview environments per pull request, environment auto-stop, per-environment RBAC, and managed cluster upgrades. Also works on GCP, Azure, Scaleway, or your existing Kubernetes cluster.
How do I migrate from App Runner to EKS step by step?
Run the migration in five phases over weeks, not one weekend: inventory and build a parity matrix, adapt each container to Kubernetes semantics, stand up a production-grade cluster, shift traffic service by service with weighted DNS, then decommission. Keep both platforms serving traffic until the last service is proven. This is the same blue-green pattern AWS documents for its own App Runner to ECS migration path, using Route 53 weighted routing.
Phase 1 - inventory and parity matrix. For every service, record the image, CPU and memory, environment variables and where secrets come from, VPC connector targets, the health check path, the custom domain, autoscaling bounds, and the IAM role it assumes. This document is the contract you migrate against.
Phase 2 - make containers Kubernetes-native. App Runner's single health check becomes three distinct Kubernetes probes: liveness, readiness, and startup, each with different failure behavior (probe docs). Add explicit resource requests and limits. Handle SIGTERM and set terminationGracePeriodSeconds so in-flight requests drain before the pod is killed (Kubernetes sends SIGTERM, waits 30 seconds by default, then SIGKILL - see the pod lifecycle docs). Stop relying on any App Runner-injected environment variables.
Phase 4 - cut over per service. Deploy each service to EKS alongside the running App Runner version. Compare latency and error rate against the live service. Then shift traffic with Route 53 weighted records in steps - 10, then 25, 50, 75, 100 - validating at each step and keeping a one-command rollback by reverting the weights.
Phase 5 - decommission. Delete the App Runner service, remove the VPC connector, revoke the IAM role, and reconcile the first full month of billing so you can see the real crossover for your account.
A mapping cheat sheet you can copy into your runbook:
App Runner concept
Kubernetes / EKS equivalent
Service
Deployment + Service + Ingress
Autoscaling config (concurrency)
HorizontalPodAutoscaler (+ KEDA for queues)
Instance role
IRSA or EKS Pod Identity
Custom domain
Ingress host + ACM certificate
Secrets injection
External Secrets or Secrets Store CSI
Health check
Liveness + readiness + startup probes
VPC connector
Native pod networking in your VPC
Timeline reality check: a 10 to 20 service migration is usually a matter of weeks, not days and not quarters, if the team already knows Kubernetes. The schedule risk is almost never the YAML. It is probes (getting the three right for slow-starting apps), secrets (rotation and least privilege), and private networking (making sure pods can reach the same databases the VPC connector did).
What breaks when you move from App Runner to Kubernetes?
The failures are predictable, and they are almost never the Deployment manifest. Expect health check semantics, secrets and IAM mapping, private networking, scaling behavior, and observability to break first. Budget review time for those five before you schedule the cutover.
Health checks. App Runner's single check becomes three Kubernetes probes. Copying one path into all three is the classic mistake: a slow-starting app fails its liveness probe during boot and ends up in a restart loop. Use a startup probe to cover the boot window, then let liveness and readiness do their separate jobs (probe docs).
IAM. App Runner instance roles do not translate one to one. Map every AWS API call the service makes to an IRSA or Pod Identity role, and test least privilege before cutover, not after an incident.
Secrets. You move from App Runner's native Secrets Manager integration to the Secrets Store CSI driver or External Secrets Operator. Decide rotation behavior explicitly, because the defaults differ.
Networking. The VPC egress connector disappears. Pods now run in your VPC directly, so re-verify security groups, NAT routing, private endpoints, and that every database path works from the pod CIDR range.
Scaling semantics. Concurrency-per-instance becomes HPA on CPU or memory, or custom metrics (HPA docs). For queue-depth workloads, add KEDA. This changes your p99 under burst, so load-test before you trust it.
Observability. No sidecars on App Runner meant CloudWatch-only logging. On EKS you now own log shipping, metrics, and trace collection, and the storage bill that comes with them.
And then there is day-2 ownership. Kubernetes version upgrades, add-on compatibility, node AMI refreshes, and CVE patching are now your calendar. EKS gives each minor version 14 months of standard support and 12 months of extended support, and that extended window costs an extra $0.50 per cluster per hour (version lifecycle). New minor versions land roughly every four months, so upgrades are a recurring commitment, not a one-time setup.
Do you have to choose between App Runner's simplicity and EKS's power?
No. The reason teams stay on App Runner past its limits is that nobody wants to hand-roll ingress, RBAC, autoscaling, upgrades, and per-pull-request environments. So put a platform layer on top of EKS and keep the git-push workflow. That is exactly the gap an internal developer platform fills.
The real choice is not managed versus unmanaged compute. It is who builds and maintains the developer experience above Kubernetes. You have three honest options:
Hand-build it with Terraform, Helm, and Argo CD. This works and gives you total control. It also costs engineer-months to build and an ongoing slice of a platform team to keep running. Fair, but not free.
Move to a hosted PaaS like Heroku, Render, Railway, or Fly.io. You trade the cluster for someone else's infrastructure, which means your cloud bill, data residency, and discounts live in their account, not yours.
Run an internal developer platform in your own account - Qovery, or alternatives like Porter and Northflank, which also deploy into a customer's own cloud.
Here is where Qovery fits, and I will only claim what we actually do. Qovery installs into your own AWS account on EKS, and equally on GCP, Azure, Scaleway, or an existing Kubernetes cluster. It gives you git-push deployments, preview environments per pull request, environment auto-stop for non-production so idle environments stop costing money, per-environment RBAC, managed cluster upgrades, and databases backed by managed cloud services. Because it is bring-your-own-cloud, the AWS bill, your Savings Plans, and your data residency stay in your account and your name, and you keep full kubectl access.
What Qovery does not do: it does not make your application architecture decisions for you. You still own workload design, how services talk to each other, and your data model. A platform layer gives you the paved road on top of Kubernetes. It does not replace engineering judgment.
Option
Who operates the cluster
Developer experience
Sidecars / GPU / batch
Preview environments
Where the cloud bill lands
Best fit
AWS App Runner
AWS
Git-push, very simple
No
No
Your account
Small HTTP services (legacy, closed to new users)
ECS on Fargate
AWS
Moderate, more config
Limited
Manual
Your account
App Runner replacement, no cluster
EKS self-managed
Your team
You build it
Full
You build it
Your account
Teams wanting total control
EKS + Argo CD in-house
Your team
Good once built
Full
You build it
Your account
Platform teams with engineer-months
Hosted PaaS (Heroku/Render/Railway/Fly.io)
The vendor
Git-push, simple
Varies
Yes
Vendor account
Small teams, no cloud ownership
Qovery on your own EKS
Qovery + you
Git-push, simple
Full (it is real K8s)
Yes, per PR
Your account
App Runner simplicity, EKS power
The honest summary: keep small request-response services on App Runner (or move them to ECS) while they still fit. Once any of the five triggers fires, move to EKS and put a platform layer on top so your developers never feel the difference.
Frequently asked questions
What are the hard limits of AWS App Runner?
The main hard limits are 4 vCPU and 12 GB of memory per service, a single container per service with no sidecars or DaemonSets, no GPU or batch support, HTTP/HTTPS-only networking with a VPC connector required for private access, and a default quota of 30 services per Region (App Runner quotas). App Runner is also now closed to new customers.
When should I migrate from AWS App Runner to Amazon EKS?
Migrate when a product requirement collides with a published limit: you need more than 4 vCPU / 12 GB, you need sidecars or multi-container pods, you need GPU or batch workloads, you need cross-service traffic policy like mTLS or canaries, or your fleet is busy enough that per-service compute costs more than a bin-packed cluster. If none of those apply, stay where you are.
Is Amazon EKS cheaper than AWS App Runner?
It depends on utilization. EKS adds a flat $0.10 per cluster per hour (about $73/month) plus nodes and networking, so a handful of mostly-idle services is cheaper on App Runner. A larger fleet that is busy most of the day is usually cheaper on EKS because you bin-pack pods onto shared, right-sized nodes and can use Spot and Graviton (EKS pricing).
How long does an App Runner to EKS migration take?
For a team that already knows Kubernetes, a 10 to 20 service migration is typically a matter of weeks when run in phases. The biggest schedule risks are health check probes on slow-starting apps, secrets rotation and least-privilege IAM, and reproducing private networking paths - not writing the Kubernetes manifests.
Does App Runner support sidecars, GPUs, or scheduled jobs?
No. App Runner runs a single container per service with no sidecars, init containers, or DaemonSets, offers no GPU or accelerator support, and has no native cron or batch primitive (App Runner architecture). Amazon EKS supports all three through multi-container pods, GPU node groups, and CronJob or KEDA.
Can I keep a git-push developer experience after moving to EKS?
Yes. Put an internal developer platform on top of EKS. Qovery, for example, installs into your own AWS account and gives you git-push deploys, preview environments per pull request, environment auto-stop, and managed cluster upgrades, so developers keep the App Runner-style workflow on real Kubernetes. It also runs on GCP, Azure, Scaleway, or an existing Kubernetes cluster.
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
Get EKS power with App Runner simplicity.
Qovery installs into your own AWS account and turns EKS into a git-push platform: preview environments per pull request, environment auto-stop, per-environment RBAC, and managed cluster upgrades. Also works on GCP, Azure, Scaleway, or your existing Kubernetes cluster.