AWS App Runner: The Complete Cheatsheet for Serverless Container Applications

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

ComponentDescription
ServiceThe primary App Runner resource that runs your application code
SourceThe code repository or container image to deploy
DeploymentA specific version of your application running in App Runner
ConfigurationSettings defining how App Runner builds and runs your application
Custom DomainUser-owned domain names mapped to the App Runner service
Auto ScalingAutomatic adjustment of computing resources based on traffic
VPC ConnectorConnection 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 TypeDescriptionBest For
Code RepositoryConnect to GitHub or AWS CodeCommitDevelopment teams using CI/CD workflows
Container ImageUse images from ECR or public registryCustom runtime environments, existing containers

Setup via AWS Console

  1. Open AWS Management Console
  2. Navigate to AWS App Runner
  3. Select “Create service”
  4. Choose source provider and repository
  5. Configure build settings (for code repositories)
  6. Configure service settings
  7. Configure networking and auto scaling
  8. 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

RuntimeVersionsBase Image
Python3.8, 3.9, 3.10, 3.11Amazon Linux 2
Node.js12, 14, 16, 18, 20Amazon Linux 2
Java8, 11, 17, 21 (Corretto)Amazon Linux 2
Go1.18, 1.19, 1.20, 1.21Amazon Linux 2
PHP8.0, 8.1, 8.2Amazon Linux 2
Ruby2.7, 3.0, 3.1, 3.2Amazon Linux 2
Dotnet6.0, 7.0, 8.0Amazon Linux 2
GenericCustom (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

ParameterDescriptionDefaultRange
MaxConcurrencyMaximum concurrent requests per instance1001-200
MaxSizeMaximum number of instances251-25
MinSizeMinimum number of instances11-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

  1. Get the DNS target from AWS console or CLI
  2. 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:

MetricDescriptionDimensions
RequestsTotal number of HTTP requestsServiceName, ServiceId
RequestLatencyTime taken to complete requestsServiceName, ServiceId
MemoryMemory usage of serviceServiceName, ServiceId, InstanceId
CPUCPU utilizationServiceName, ServiceId, InstanceId
5xxErrorsCount of 5xx errorsServiceName, ServiceId
4xxErrorsCount of 4xx errorsServiceName, 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

ChallengeSolution
Slow cold startsIncrease minimum instance count, optimize application startup
Connection timeouts to VPC resourcesCheck security groups, network ACLs, and routing tables
Build failuresReview build logs in CloudWatch, ensure build dependencies are available
High latencyCheck application performance, consider higher CPU/memory configuration
Auto scaling delaysConfigure lower MaxConcurrency for faster scale-out
Custom domain certificate issuesVerify DNS configuration, check domain validation status
Memory limits reachedIncrease memory allocation, optimize application memory usage
Access denied to resourcesReview IAM roles, ensure proper permissions
Environment variable issuesCheck for typos, confirm variables are defined in the right scope
Missing secretsVerify secret ARNs and names, check service role permissions

Best Practices

  1. Configuration as Code: Store apprunner.yaml in your code repository for repeatable deployments

  2. Immutable Infrastructure: Treat App Runner services as immutable—update code instead of modifying running instances

  3. Health Checks: Implement and leverage health checks to ensure application readiness

  4. Separation of Environments: Use separate App Runner services for different environments (dev, staging, prod)

  5. Right-size Resources: Configure appropriate CPU and memory for your workload

  6. Observability: Implement proper logging, use structured log formats for better querying

  7. Security: Follow least privilege principle for IAM roles, secure secrets properly

  8. Testing: Test auto-scaling behavior and service limits before production deployment

  9. Application Design: Design applications to be stateless and handle graceful shutdown

  10. Cost Monitoring: Set up CloudWatch Alarms for cost-related metrics

AWS App Runner vs. Other AWS Services

CriteriaApp RunnerECS/FargateLambdaElastic Beanstalk
Management OverheadMinimalModerateMinimalLow to Moderate
Container SupportYesYesLimitedYes
Cold StartSecondsSecondsMilliseconds to secondsMinutes
ScalingAutomaticConfigurableAutomaticConfigurable
Cost ModelPay for running instancesPay for running tasksPay per requestPay for EC2 instances
Max Execution TimeUnlimitedUnlimited15 minutesUnlimited
Network OptionsPublic, VPCPublic, VPCPublic, VPCPublic, VPC
Configuration ComplexityLowHighLowMedium
Best ForWeb apps, APIs with moderate trafficComplex containerized appsEvent-driven functionsTraditional web applications

Resources for Further Learning

Official Documentation

Tutorials and Workshops

Additional Resources

Scroll to Top