Introduction
AWS App Runner is a fully managed service that makes it easy to deploy containerized web applications and APIs, without requiring expertise in AWS infrastructure. Launched in 2021, App Runner automatically builds and deploys your code, handles load balancing, scaling, and manages traffic encryption—all with simple configuration rather than complex infrastructure setup. It’s ideal for developers who want to focus on code rather than operations, providing a streamlined path from source code to scalable, secure web application.
Core Concepts
Key Components
| Component | Description |
|---|---|
| Service | The primary App Runner resource that runs your application code |
| Source | The code repository or container image to deploy |
| Deployment | A specific version of your application running in App Runner |
| Configuration | Settings defining how App Runner builds and runs your application |
| Custom Domain | User-owned domain names mapped to the App Runner service |
| Auto Scaling | Automatic adjustment of computing resources based on traffic |
| VPC Connector | Connection to resources in your Amazon VPC |
Service Architecture
┌────────────────────────────────────────────────────────────┐
│ AWS App Runner Service │
│ │
│ ┌────────────┐ ┌────────────┐ ┌─────────────────┐ │
│ │ Source │───►│ Build │───►│ Service Runtime │ │
│ │ Repository │ │ Environment│ │ Environment │ │
│ └────────────┘ └────────────┘ └─────────────────┘ │
│ ▲ │ │
│ │ ▼ │
│ ┌──────────────┐ ┌──────────────┐ │
│ │ Automatic │ │ Automatic │ │
│ │ Deployment │◄──────────────────►│ Scaling │ │
│ └──────────────┘ └──────────────┘ │
│ │ │
└────────────────────────────────────────────┼───────────────┘
▼
┌───────────────┐ ┌─────────────────┐
│ HTTPS Ingress │◄────────────┤ Public Access │
└───────────────┘ └─────────────────┘
▲
│
┌──────────────┐
│ Users │
└──────────────┘
Setting Up App Runner
Source Configuration Types
| Source Type | Description | Best For |
|---|---|---|
| Code Repository | Connect to GitHub or AWS CodeCommit | Development teams using CI/CD workflows |
| Container Image | Use images from ECR or public registry | Custom runtime environments, existing containers |
Setup via AWS Console
- Open AWS Management Console
- Navigate to AWS App Runner
- Select “Create service”
- Choose source provider and repository
- Configure build settings (for code repositories)
- Configure service settings
- Configure networking and auto scaling
- Review and create service
Setup via AWS CLI
# Create service from GitHub source code repository
aws apprunner create-service \
--service-name my-app \
--source-configuration '{
"AuthenticationConfiguration": {
"ConnectionArn": "arn:aws:apprunner:region:account-id:connection/connection-name"
},
"AutoDeploymentsEnabled": true,
"CodeRepository": {
"RepositoryUrl": "https://github.com/username/repo",
"SourceCodeVersion": {
"Type": "BRANCH",
"Value": "main"
},
"CodeConfiguration": {
"ConfigurationSource": "REPOSITORY",
"CodeConfigurationValues": {
"Runtime": "PYTHON_3",
"BuildCommand": "pip install -r requirements.txt",
"StartCommand": "python app.py",
"Port": "8080"
}
}
}
}' \
--instance-configuration '{
"Cpu": "1 vCPU",
"Memory": "2 GB"
}' \
--auto-scaling-configuration-arn "arn:aws:apprunner:region:account-id:autoscalingconfiguration/name/revision"
# Create service from a container image
aws apprunner create-service \
--service-name my-container-app \
--source-configuration '{
"ImageRepository": {
"ImageIdentifier": "account-id.dkr.ecr.region.amazonaws.com/repository:tag",
"ImageConfiguration": {
"Port": "8080",
"RuntimeEnvironmentVariables": {
"ENV_VAR_1": "value1",
"ENV_VAR_2": "value2"
}
},
"ImageRepositoryType": "ECR"
}
}' \
--instance-configuration '{
"Cpu": "1 vCPU",
"Memory": "2 GB"
}'
Setup via CloudFormation
Resources:
MyAppRunnerService:
Type: AWS::AppRunner::Service
Properties:
ServiceName: my-app-service
SourceConfiguration:
AuthenticationConfiguration:
ConnectionArn: !Sub arn:aws:apprunner:${AWS::Region}:${AWS::AccountId}:connection/my-connection
AutoDeploymentsEnabled: true
CodeRepository:
RepositoryUrl: https://github.com/username/repo
SourceCodeVersion:
Type: BRANCH
Value: main
CodeConfiguration:
ConfigurationSource: REPOSITORY
CodeConfigurationValues:
Runtime: PYTHON_3
BuildCommand: pip install -r requirements.txt
StartCommand: python app.py
Port: 8080
InstanceConfiguration:
Cpu: 1 vCPU
Memory: 2 GB
Tags:
- Key: Environment
Value: Development
Configuration Files
apprunner.yaml
For repository-based code deployments, App Runner can use a configuration file in your repository:
version: 1.0
runtime: python3
build:
commands:
pre-build:
- echo Installing dependencies...
- pip install -r requirements.txt
build:
- echo Running tests...
- pytest
post-build:
- echo Build completed on `date`
run:
command: python app.py
network:
port: 8080
env: APP_PORT
env:
- name: MY_ENV_VAR
value: my-value
- name: ENVIRONMENT
value: production
- name: SECRET_KEY
valueFrom: /myapp/secrets/secret-key
secrets:
- name: DATABASE_PASSWORD
valueFrom: /myapp/secrets/db-password
Supported Runtimes
| Runtime | Versions | Base Image |
|---|---|---|
| Python | 3.8, 3.9, 3.10, 3.11 | Amazon Linux 2 |
| Node.js | 12, 14, 16, 18, 20 | Amazon Linux 2 |
| Java | 8, 11, 17, 21 (Corretto) | Amazon Linux 2 |
| Go | 1.18, 1.19, 1.20, 1.21 | Amazon Linux 2 |
| PHP | 8.0, 8.1, 8.2 | Amazon Linux 2 |
| Ruby | 2.7, 3.0, 3.1, 3.2 | Amazon Linux 2 |
| Dotnet | 6.0, 7.0, 8.0 | Amazon Linux 2 |
| Generic | Custom (bring your own packages) | Amazon Linux 2 |
Auto Scaling
Configuration Options
# Create Auto Scaling configuration
aws apprunner create-auto-scaling-configuration \
--auto-scaling-configuration-name my-scaling-config \
--max-concurrency 100 \
--max-size 10 \
--min-size 1
# Associate with a service during creation or update
aws apprunner update-service \
--service-arn "arn:aws:apprunner:region:account-id:service/service-name" \
--auto-scaling-configuration-arn "arn:aws:apprunner:region:account-id:autoscalingconfiguration/name/revision"
Auto Scaling Parameters
| Parameter | Description | Default | Range |
|---|---|---|---|
| MaxConcurrency | Maximum concurrent requests per instance | 100 | 1-200 |
| MaxSize | Maximum number of instances | 25 | 1-25 |
| MinSize | Minimum number of instances | 1 | 1-25 |
Networking
VPC Integration
# Create a VPC Connector
aws apprunner create-vpc-connector \
--vpc-connector-name my-vpc-connector \
--subnets subnet-id-1 subnet-id-2 \
--security-groups sg-id-1 sg-id-2
# Associate with a service
aws apprunner update-service \
--service-arn "arn:aws:apprunner:region:account-id:service/service-name" \
--network-configuration '{
"EgressConfiguration": {
"EgressType": "VPC",
"VpcConnectorArn": "arn:aws:apprunner:region:account-id:vpcconnector/connector-name"
}
}'
Custom Domains
# Associate a custom domain
aws apprunner associate-custom-domain \
--service-arn "arn:aws:apprunner:region:account-id:service/service-name" \
--domain-name "myapp.example.com" \
--enable-www-subdomain
# Disassociate a custom domain
aws apprunner disassociate-custom-domain \
--service-arn "arn:aws:apprunner:region:account-id:service/service-name" \
--domain-name "myapp.example.com"
Custom Domain DNS Configuration
- Get the DNS target from AWS console or CLI
- Create a CNAME record in your DNS provider:
- Name: myapp.example.com
- Type: CNAME
- Value: d-abcdefghij.us-east-1.awsapprunner.com
Security
IAM Permissions
Service Instance Role
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:GetObject",
"s3:ListBucket"
],
"Resource": [
"arn:aws:s3:::my-bucket",
"arn:aws:s3:::my-bucket/*"
]
},
{
"Effect": "Allow",
"Action": [
"secretsmanager:GetSecretValue"
],
"Resource": [
"arn:aws:secretsmanager:region:account-id:secret:app-secrets-*"
]
}
]
}
Access Role for ECR Images
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"ecr:GetDownloadUrlForLayer",
"ecr:BatchCheckLayerAvailability",
"ecr:BatchGetImage"
],
"Resource": "arn:aws:ecr:region:account-id:repository/repository-name"
},
{
"Effect": "Allow",
"Action": "ecr:GetAuthorizationToken",
"Resource": "*"
}
]
}
Secrets Management
Using AWS Systems Manager Parameter Store
# Create a parameter in Systems Manager
aws ssm put-parameter \
--name "/myapp/secrets/db-password" \
--value "your-secure-password" \
--type SecureString
# Reference in apprunner.yaml
# run:
# secrets:
# - name: DATABASE_PASSWORD
# valueFrom: /myapp/secrets/db-password
Using AWS Secrets Manager
# Create a secret in Secrets Manager
aws secretsmanager create-secret \
--name "myapp/database-credentials" \
--secret-string '{"username":"admin","password":"your-secure-password"}'
# Reference in apprunner.yaml
# run:
# secrets:
# - name: DATABASE_CREDENTIALS
# valueFrom: arn:aws:secretsmanager:region:account-id:secret:myapp/database-credentials
Operations and Maintenance
Service Management
# List all App Runner services
aws apprunner list-services
# Describe a service
aws apprunner describe-service \
--service-arn "arn:aws:apprunner:region:account-id:service/service-name"
# Pause a service
aws apprunner pause-service \
--service-arn "arn:aws:apprunner:region:account-id:service/service-name"
# Resume a service
aws apprunner resume-service \
--service-arn "arn:aws:apprunner:region:account-id:service/service-name"
# Delete a service
aws apprunner delete-service \
--service-arn "arn:aws:apprunner:region:account-id:service/service-name"
Deployments
# Start a manual deployment
aws apprunner start-deployment \
--service-arn "arn:aws:apprunner:region:account-id:service/service-name"
# List deployments for a service
aws apprunner list-operations \
--service-arn "arn:aws:apprunner:region:account-id:service/service-name"
Logs and Monitoring
CloudWatch Logs
App Runner automatically sends logs to CloudWatch Logs:
/aws/apprunner/service-name/service-id/service– Application logs/aws/apprunner/service-name/service-id/deployment– Deployment logs
# Get logs for a service using CloudWatch Logs Insights
aws logs start-query \
--log-group-name "/aws/apprunner/service-name/service-id/service" \
--start-time `date -d "1 hour ago" +%s` \
--end-time `date +%s` \
--query-string "fields @timestamp, @message | sort @timestamp desc | limit 20"
CloudWatch Metrics
Key metrics available in CloudWatch:
| Metric | Description | Dimensions |
|---|---|---|
| Requests | Total number of HTTP requests | ServiceName, ServiceId |
| RequestLatency | Time taken to complete requests | ServiceName, ServiceId |
| Memory | Memory usage of service | ServiceName, ServiceId, InstanceId |
| CPU | CPU utilization | ServiceName, ServiceId, InstanceId |
| 5xxErrors | Count of 5xx errors | ServiceName, ServiceId |
| 4xxErrors | Count of 4xx errors | ServiceName, ServiceId |
Cost Optimization
- Service Level: Pause unused services to stop billing
- Instance Size: Select appropriate CPU/Memory for your workload
- Auto Scaling: Configure minimum instance count appropriately
- Concurrent Connections: Optimize MaxConcurrency for efficient resource usage
- Reserved Concurrency: Use Reserved Concurrency for predictable workloads
- Deploy Frequency: Minimize unnecessary deployments (each build consumes resources)
Common Challenges and Solutions
| Challenge | Solution |
|---|---|
| Slow cold starts | Increase minimum instance count, optimize application startup |
| Connection timeouts to VPC resources | Check security groups, network ACLs, and routing tables |
| Build failures | Review build logs in CloudWatch, ensure build dependencies are available |
| High latency | Check application performance, consider higher CPU/memory configuration |
| Auto scaling delays | Configure lower MaxConcurrency for faster scale-out |
| Custom domain certificate issues | Verify DNS configuration, check domain validation status |
| Memory limits reached | Increase memory allocation, optimize application memory usage |
| Access denied to resources | Review IAM roles, ensure proper permissions |
| Environment variable issues | Check for typos, confirm variables are defined in the right scope |
| Missing secrets | Verify secret ARNs and names, check service role permissions |
Best Practices
Configuration as Code: Store
apprunner.yamlin your code repository for repeatable deploymentsImmutable Infrastructure: Treat App Runner services as immutable—update code instead of modifying running instances
Health Checks: Implement and leverage health checks to ensure application readiness
Separation of Environments: Use separate App Runner services for different environments (dev, staging, prod)
Right-size Resources: Configure appropriate CPU and memory for your workload
Observability: Implement proper logging, use structured log formats for better querying
Security: Follow least privilege principle for IAM roles, secure secrets properly
Testing: Test auto-scaling behavior and service limits before production deployment
Application Design: Design applications to be stateless and handle graceful shutdown
Cost Monitoring: Set up CloudWatch Alarms for cost-related metrics
AWS App Runner vs. Other AWS Services
| Criteria | App Runner | ECS/Fargate | Lambda | Elastic Beanstalk |
|---|---|---|---|---|
| Management Overhead | Minimal | Moderate | Minimal | Low to Moderate |
| Container Support | Yes | Yes | Limited | Yes |
| Cold Start | Seconds | Seconds | Milliseconds to seconds | Minutes |
| Scaling | Automatic | Configurable | Automatic | Configurable |
| Cost Model | Pay for running instances | Pay for running tasks | Pay per request | Pay for EC2 instances |
| Max Execution Time | Unlimited | Unlimited | 15 minutes | Unlimited |
| Network Options | Public, VPC | Public, VPC | Public, VPC | Public, VPC |
| Configuration Complexity | Low | High | Low | Medium |
| Best For | Web apps, APIs with moderate traffic | Complex containerized apps | Event-driven functions | Traditional web applications |
