AWS App Runner Explained: What It Is, How It Works, and When to Use It
AWS App Runner is a fully managed container service that deploys web applications and APIs with almost no configuration. You provide a container image or source code repository, and App Runner handles building, deploying, scaling, load balancing, and HTTPS. Within minutes, you have a running service at a public URL.
It is designed for developers who want to run a containerised web service on AWS without learning ECS task definitions, Application Load Balancer configuration, or Auto Scaling groups. If you have used Heroku or Railway, App Runner fills a similar role: a platform-as-a-service experience built on top of AWS infrastructure.
App Runner is not the right tool for every workload. It does not support multiple containers per service, provides limited VPC control, and is built specifically for HTTP services rather than background workers or batch jobs. See the compute decision guide for a broader framework to choose between App Runner, Lambda, ECS, and EC2.
App Runner in plain English
Imagine you have a Django or FastAPI application packaged as a Docker image. You want it running on the internet with HTTPS and automatic scaling. Without App Runner, deploying that image to AWS involves: pushing it to Amazon ECR, creating an ECS cluster, writing a task definition, creating a service, provisioning an Application Load Balancer, attaching a target group, requesting a TLS certificate, and writing Auto Scaling policies. Each one is a separate AWS resource to understand and maintain.
With App Runner, you point it at your image or source repo, configure CPU and memory, and deploy. App Runner creates all of those components internally and hands you a URL. You never see the load balancer or the cluster. They exist, but App Runner manages them.
Analogy
App Runner is like a fully furnished apartment. You bring your belongings (your application image or source code) and move in immediately. The furniture, utilities, and maintenance are included. ECS Fargate is like renting an empty apartment: more work to set up, but you can arrange it exactly how you want. EC2 is like buying land and building the house yourself.
Why App Runner exists
Before App Runner launched in 2021, running a containerised web service on AWS had a meaningful learning curve. Lambda solves the “no infrastructure” problem but imposes a 15-minute timeout and a function-based programming model that does not fit a standard HTTP server. ECS Fargate removes the need to manage EC2 instances but still requires you to understand clusters, task definitions, services, and load balancers.
App Runner targets the gap: a fully managed platform that accepts a standard container image or source code and requires no cluster, load balancer, or certificate configuration. The trade-off is reduced control; App Runner makes networking and infrastructure decisions that you cannot override without moving to a different service. For many web applications, that trade-off is well worth it.
How App Runner works
When you create an App Runner service, it follows this sequence:
- Source: You provide either a container image URI (from ECR or a public registry) or a GitHub repository URL with runtime settings.
- Build: For source-code deployments, App Runner builds the container image using a managed build environment. For image-based deployments, it pulls the image from the registry.
- Deploy: App Runner provisions instances and starts your application container, injecting any environment variables you configured.
- Route: A fully managed load balancer accepts incoming HTTPS traffic and distributes it across running instances. You do not create or configure this load balancer; App Runner manages it internally.
- Scale: App Runner monitors concurrent request count per instance. When requests exceed your MaxConcurrency threshold, it starts new instances. When traffic drops, it scales back in.
- Observe: Application logs flow automatically to CloudWatch Logs. CloudWatch Metrics reports request counts, latency, active instance counts, and HTTP response code distribution.
- Update: When you push a new image to ECR or merge to the connected GitHub branch, App Runner detects the change and performs a rolling deployment to the new version.
Your application only needs to listen on the port you specify (typically 8000 or 8080) and respond to HTTP requests. Everything else is managed by App Runner.
Two deployment paths
App Runner accepts applications in two forms.
Source code repository
Connect App Runner to a GitHub repository. You specify the branch, runtime, build command, and start command. App Runner builds the container image in a managed environment and deploys it. When you push to the connected branch, App Runner automatically rebuilds and redeploys.
Supported runtimes include Python, Node.js, Java (Corretto), Go, .NET, PHP, and Ruby. This path is the fastest way to get from code to production without setting up a Docker build pipeline. There is no Dockerfile to write and no need to configure GitHub Actions before your first deployment.
The limitation: the managed build environment has fixed dependency support. For applications with complex system-level requirements or non-standard binaries, the container image path gives you more control.
Container image
Provide a container image URI from Amazon ECR (private or public) or a public registry such as Docker Hub. App Runner pulls the image and runs it. You are responsible for building and pushing the image; App Runner only runs it.
This is the recommended path for production deployments. You control the entire build environment, runtime, and dependency set. See Container Images in AWS for guidance on building production-ready Docker images.
Enable automatic deployments and App Runner polls ECR for new image versions. When it detects a new image, it deploys without any manual step. This pairs naturally with a CI/CD pipeline where pushing a tagged image to ECR is the final deploy step.
If you use the :latest tag with automatic deployments, App Runner re-deploys every time the tag is updated in ECR. For more controlled rollouts, push with a versioned tag (:v1.2.3 or a Git SHA) and update the service to point to the new tag explicitly. This gives you a clear deployment history and easier rollbacks.
# Create an App Runner service from a private ECR image
aws apprunner create-service \
--service-name my-web-api \
--source-configuration '{
"ImageRepository": {
"ImageIdentifier": "123456789012.dkr.ecr.us-east-1.amazonaws.com/my-app:latest",
"ImageRepositoryType": "ECR",
"ImageConfiguration": {
"Port": "8000",
"RuntimeEnvironmentVariables": {
"ENVIRONMENT": "production"
}
}
},
"AutoDeploymentsEnabled": true,
"AuthenticationConfiguration": {
"AccessRoleArn": "arn:aws:iam::123456789012:role/AppRunnerECRAccessRole"
}
}' \
--instance-configuration '{
"Cpu": "1 vCPU",
"Memory": "2 GB",
"InstanceRoleArn": "arn:aws:iam::123456789012:role/AppRunnerInstanceRole"
}'The response includes a service URL, such as abc123.us-east-1.awsapprunner.com, once the service finishes deploying.
When to use App Runner
App Runner is a good fit when:
- You are deploying a web application or HTTP API. A Django app, a FastAPI service, a Node.js REST API: App Runner is purpose-built for this pattern.
- You want minimal infrastructure to configure. A small team or solo developer who needs something running on AWS without spending days learning ECS.
- Your application runs as a single container. Standard web services (one process, one container) fit App Runner’s model exactly.
- You want automatic deployments without a separate deploy step. App Runner’s built-in ECR polling and GitHub integration removes the need for a dedicated deployment pipeline on many projects.
- Traffic is variable or unpredictable. Concurrency-based auto scaling handles spikes without pre-provisioning capacity.
- You are migrating from a PaaS. App Runner is the closest AWS equivalent to Heroku or Railway. Teams moving from those platforms will find the operational model familiar.
Concrete examples: a B2B SaaS API backend, an internal admin tool, a mobile app backend, a Django or FastAPI service with moderate traffic, or a prototype you need running quickly on AWS.
When not to use App Runner
- You need multiple containers per service instance. App Runner runs one container per instance. Sidecar patterns (an application alongside an Envoy proxy, a log forwarder, or a monitoring agent) are not supported. Use ECS Fargate tasks for multi-container workloads.
- You need fine-grained VPC control. The VPC connector gives egress access to your VPC, but you cannot control ingress routing, place instances in specific subnets, or use private load balancers. ECS Fargate gives you full VPC control.
- Your workload is event-driven rather than HTTP-driven. If you process SQS messages, respond to S3 events, or run scheduled jobs, Lambda is a better fit. App Runner is built for handling HTTP requests.
- You need background workers without HTTP traffic. App Runner scales based on request concurrency. A worker process with no incoming requests has no scale signal to stay running. Use AWS Batch or ECS with an SQS-driven task pattern instead.
- You need Kubernetes-native tooling. If your team relies on Helm, Kustomize, or Kubernetes operators, Amazon EKS is the right environment. App Runner is not Kubernetes.
- Cost at very high sustained volumes. At consistently high request volumes, ECS Fargate or a right-sized EC2 deployment may be cheaper per unit of compute. Model the costs before committing App Runner to high-throughput production workloads.
A common mistake is deploying an App Runner service and pointing it at a private RDS database, then seeing connection timeouts with no obvious error. This happens because App Runner instances run outside your VPC by default. They cannot reach any private resource until you attach a VPC connector. Configure the VPC connector before deploying your application, not after.
IAM, networking, scaling, and operations
IAM roles
App Runner uses two separate IAM roles:
Access role: Used by App Runner to pull your image from a private ECR repository. The trust policy must allow the principal
build.apprunner.amazonaws.com. Attach the AWS-managed policyAWSAppRunnerServicePolicyForECRAccess. Not required if your image is on a public registry.Instance role: Used by your application code at runtime. If your application calls DynamoDB, S3, Secrets Manager, or any other AWS service, those permissions go on the instance role. The trust policy must allow the principal
tasks.apprunner.amazonaws.com. Apply least privilege: grant only the permissions the application actually uses, scoped to specific resources.
Do not put AWS credentials in environment variables. Application code running on App Runner can retrieve temporary credentials from the instance metadata endpoint using the instance role, the same way ECS tasks do. Hard-coded credentials in environment variables expire, rotate poorly, and are a security risk if the variables are ever logged or exposed.
Auto scaling
App Runner scales based on the number of concurrent requests being handled per instance. You configure three values in an auto scaling configuration:
- MinSize: Minimum instances kept running. Default is 1. Set to 0 to allow scale-to-zero.
- MaxSize: Maximum instances App Runner will add.
- MaxConcurrency: Concurrent requests per instance before a new instance starts. Default is 100. Lower this for memory-intensive workloads that cannot safely handle 100 simultaneous requests.
Setting MinSize to 0 saves cost when idle but introduces cold start latency: App Runner must start a container before the first request is served after an idle period. For user-facing production APIs, keep MinSize at 1 or higher. Reserve scale-to-zero for development environments or internal tools where occasional slow first-response times are acceptable.
VPC connector and private resource access
By default, App Runner instances run in an AWS-managed network. They can reach public AWS endpoints but cannot access resources in your private VPC: RDS databases, ElastiCache clusters, or internal services.
A VPC connector attaches App Runner’s outbound traffic to subnets and security groups in your VPC. Once attached, your application can connect to a private RDS database on port 5432 or an ElastiCache cluster on port 6379. The security group on the database must allow inbound connections from the security group assigned to the VPC connector.
Custom domains
App Runner provides a default HTTPS endpoint at *.awsapprunner.com. To use your own domain, associate it with the service through the console or CLI. App Runner requests a TLS certificate automatically from AWS Certificate Manager. You add CNAME records at your DNS provider or in Route 53 to complete the setup. Certificate renewal is automatic.
Observability
App Runner delivers application logs to CloudWatch Logs automatically, with no agent needed. System events (deployments, scaling activity, health check results) are written to a separate log group. CloudWatch Metrics tracks request count, request latency (p50, p90, p99), active instance count, and HTTP response code distribution.
For distributed tracing, instrument your application with the AWS X-Ray SDK. App Runner does not inject traces automatically; the instrumentation lives in your application code.
App Runner vs Lambda vs ECS Fargate
| App Runner | Lambda | ECS Fargate | |
|---|---|---|---|
| Setup complexity | Very low | Low | Medium |
| Cold starts | None when MinSize ≥ 1 | Yes, unless provisioned concurrency | None |
| Runtime limit | No limit | 15 minutes | No limit |
| Scales to zero | Optional (MinSize = 0) | Always | Requires extra configuration |
| Networking control | VPC connector (egress only) | Full VPC config | Full VPC config |
| Multiple containers | No, one per instance | No | Yes, multiple per task |
| Runtime model | Long-running HTTP service | Short-lived function | Long-running container |
| Auto-deploy on image push | Built-in | Manual or CI/CD | Manual or CI/CD |
| Best fit | Web apps and APIs | Event-driven tasks | Multi-container or complex-networking workloads |
For most web applications and APIs, App Runner is the simplest starting point on AWS. When you outgrow its networking model or need multiple containers, ECS Fargate is the natural next step (more complexity, but full control). Lambda is the right choice when the work is event-driven and short-lived rather than request-handling. For the full decision framework including EC2, see the EC2 vs Lambda vs containers guide.
Common mistakes
Setting MinSize to 0 for a user-facing production service. Scale-to-zero is a cost saving, not a safe default for user traffic. After an idle period, the first request waits while App Runner starts a new instance. For any service where response time matters, keep MinSize at 1 or higher.
Forgetting the access role for private ECR images. Without an access role that includes
AWSAppRunnerServicePolicyForECRAccess, App Runner cannot pull from a private ECR repository. The deployment fails immediately with an authentication error. This is the most common first-deployment problem.Pointing the application at a private database without a VPC connector. App Runner instances cannot reach resources in your VPC by default. If your application connects to a private RDS endpoint and no VPC connector is attached, connections time out. Configure the VPC connector before deploying.
Using App Runner for workloads that need multiple containers. App Runner runs one container per service instance. If you need a sidecar (a proxy, log forwarder, or monitoring agent), App Runner cannot support that pattern. Use ECS Fargate tasks instead.
Calling AWS services without an instance role. Application code that calls DynamoDB, S3, or Secrets Manager needs an instance role with the appropriate permissions. Without one, those API calls fail with credential errors. Do not work around this by embedding IAM credentials in environment variables; use the instance role.
Frequently asked questions
What is AWS App Runner?
AWS App Runner is a fully managed service that builds, deploys, and runs containerised web applications and APIs. You provide source code from a GitHub repository or a container image from ECR, and App Runner handles build, deployment, load balancing, auto scaling, TLS termination, and a public HTTPS endpoint. There is no cluster, load balancer, or certificate to configure.
How does App Runner scale?
App Runner scales based on concurrent request count. It adds new instances when the number of simultaneous in-flight requests per instance exceeds your MaxConcurrency setting, and scales back in when traffic drops. With MinSize set to 0, App Runner can scale to zero when idle, but the first request after the idle period triggers a cold start. For user-facing production services, set MinSize to 1 or higher.
What is the difference between App Runner and ECS Fargate?
App Runner is more opinionated and far simpler: it gives you a complete managed platform with built-in load balancing, TLS, and auto scaling. ECS Fargate provides more control, including custom VPC networking, multiple containers per task, more scaling options, and broader AWS service integration. Choose App Runner when operational simplicity matters more than flexibility; choose ECS Fargate when you need fine-grained control.
Does App Runner support custom domains?
Yes. You can connect a custom domain to an App Runner service through the AWS console or CLI. App Runner provisions a TLS certificate automatically via AWS Certificate Manager. You add CNAME records at your DNS registrar or in Route 53 to point your domain at the App Runner endpoint. Certificate renewal is handled automatically.
Can App Runner connect to a private RDS database?
Yes, but it requires a VPC connector. By default, App Runner instances run in an AWS-managed network with no access to your VPC. A VPC connector routes App Runner outbound traffic through subnets and security groups in your VPC, enabling connections to private RDS instances, ElastiCache clusters, and other internal resources. The security group on the database must allow inbound traffic from the App Runner security group.