AWS Elastic Beanstalk: Deploy Web Apps Without Thinking About Infrastructure
Elastic Beanstalk sits between raw EC2 and a fully managed PaaS. You upload application code, pick a runtime, and Beanstalk provisions the EC2 instances, load balancer, Auto Scaling group, and CloudWatch alarms. You retain full access to the underlying resources and can customise them — but the defaults are sensible and get you running in minutes.
It is not the right tool for every team or every stage of growth, but for developers who want AWS-quality infrastructure without hiring DevOps, it is a practical starting point.
What Beanstalk Manages For You
Your Code Upload (.zip or Git) │ ▼┌──────────────────────────────────────────────────────────┐│ Elastic Beanstalk Environment ││ ││ Application Load Balancer ││ │ ││ Auto Scaling Group ││ ├── EC2 Instance (your code running) ││ ├── EC2 Instance (your code running) ││ └── EC2 Instance (your code running) ││ ││ CloudWatch Alarms (CPU, request count) ││ CloudWatch Logs (application output) ││ EC2 Security Groups (auto-configured) ││ IAM Instance Profile (auto-created) │└──────────────────────────────────────────────────────────┘Beanstalk creates all of this from a single eb create command or a console click.
Supported Platforms
Each Beanstalk platform is a combination of OS + runtime:
- Python 3.11, 3.12 on Amazon Linux 2023
- Node.js 18, 20 on Amazon Linux 2023
- Java 11, 17, 21 (Corretto) on Amazon Linux 2023
- .NET 8 on Windows Server 2022
- PHP 8.1, 8.2 on Amazon Linux 2023
- Ruby 3.2, 3.3 on Amazon Linux 2023
- Go 1.21 on Amazon Linux 2023
- Docker (single container or Docker Compose) on Amazon Linux 2023
The Docker platform is the most flexible — if your app runs in a container, Beanstalk can run it regardless of the language.
Deploying Your First Application
Install the EB CLI:
pip install awsebcliFor a Python Flask application:
from flask import Flask, jsonifyapplication = Flask(__name__) # Must be named 'application' for Beanstalk
@application.route('/health')def health(): return jsonify({'status': 'ok'})
@application.route('/')def index(): return jsonify({'message': 'Hello from Elastic Beanstalk'})
if __name__ == '__main__': application.run(port=8000)Flask==3.0.0gunicorn==21.2.0# Procfile (tells Beanstalk how to start the app)web: gunicorn --bind 0.0.0.0:8000 application:application# Initialise and deployeb init my-flask-app --platform python-3.12 --region us-east-1eb create production --instance-type t3.small --min-instances 2 --max-instances 6That creates a production-ready environment. Beanstalk provisions the load balancer and Auto Scaling group. Update the application:
# Deploy new codeeb deploy
# Or specify environment nameeb deploy productionEnvironment Tiers
Web Server Environment: Standard web application setup with an ALB in front of an ASG. The default and most common tier.
Worker Environment: Processes jobs from an SQS queue. Beanstalk provides a daemon process that polls SQS and POST requests to http://localhost/ for each message. Your application does not need SQS SDK code — it just handles HTTP POST requests. Useful for background processing without building a separate worker infrastructure.
Deployment Policies
Beanstalk supports multiple deployment strategies that control how it rolls out new versions:
ALL AT ONCE: Old → New (all instances simultaneously) Fastest, but causes downtime if deployment fails. Use only for dev environments.
ROLLING: [Old][Old][Old][Old] [New][New][Old][Old] [New][New][New][New] No extra cost. Temporary reduced capacity.
ROLLING WITH ADDITIONAL BATCH: [Old][Old][Old][Old] [Old][Old][Old][Old][New] ← extra batch added [New][New][New][Old] [New][New][New][New] Full capacity throughout. Costs extra for duration.
IMMUTABLE: New ASG created alongside existing, tested, then swapped. Safest. Full capacity. Can roll back by terminating new ASG.
TRAFFIC SPLITTING: New version deployed to new instances. % traffic shifted to new instances (canary release). Monitors health, completes shift or rolls back.For production, rolling with additional batch or immutable are the recommended choices. All At Once is never appropriate for production.
# Deploy with immutable strategyaws elasticbeanstalk update-environment \ --environment-name production \ --option-settings Namespace=aws:elasticbeanstalk:command,OptionName=DeploymentPolicy,Value=ImmutableCustomising with .ebextensions
.ebextensions is a directory in your application bundle with YAML configuration files. These run during environment provisioning and deployment, giving you control over OS packages, files, commands, and AWS resource configuration.
packages: yum: git: [] postgresql-devel: []
commands: 01-set-timezone: command: "timedatectl set-timezone UTC" test: "[ \"$(timedatectl | grep 'Time zone' | awk '{print $3}')\" != 'UTC' ]"option_settings: aws:autoscaling:asg: MinSize: 2 MaxSize: 8 aws:ec2:instances: InstanceTypes: t3.small,t3.medium aws:elasticbeanstalk:environment:proxy: ProxyServer: nginx aws:elasticbeanstalk:environment:proxy:staticfiles: /static: staticfiles: "/opt/elasticbeanstalk/tasks/taillogs.d/app-logs.conf": mode: "000644" content: | /var/log/app/application.logThe staticfiles setting tells nginx to serve /static/ files directly without proxying to your application, which reduces load on the app server.
Environment Variables and Secrets
Set environment properties in the Beanstalk console, CLI, or .ebextensions:
aws elasticbeanstalk update-environment \ --environment-name production \ --option-settings \ Namespace=aws:elasticbeanstalk:application:environment,OptionName=DATABASE_URL,Value=postgres://... \ Namespace=aws:elasticbeanstalk:application:environment,OptionName=NODE_ENV,Value=productionFor sensitive values, do not put secrets in option settings (they appear in the console). Instead, reference Secrets Manager from your application code and grant the Beanstalk instance profile permission to read the secret.
Database Integration
Beanstalk can create an RDS database as part of the environment. This is convenient for development but problematic for production — the database lifecycle is tied to the environment. Deleting the environment deletes the database.
For production:
- Create RDS outside of Beanstalk in a separate VPC stack
- Put the database URL in Beanstalk environment properties (or better, Secrets Manager)
- Configure the Beanstalk environment’s VPC and security groups to allow the instance profile to reach the database
# Create environment with existing VPC/RDSaws elasticbeanstalk create-environment \ --application-name my-app \ --environment-name production \ --solution-stack-name "64bit Amazon Linux 2023 v4.0.0 running Python 3.12" \ --option-settings \ Namespace=aws:ec2:vpc,OptionName=VPCId,Value=vpc-0a1b2c \ Namespace=aws:ec2:vpc,OptionName=Subnets,Value="subnet-0a1b2c,subnet-0d4e5f" \ Namespace=aws:ec2:vpc,OptionName=ELBSubnets,Value="subnet-elb-0a1b2c,subnet-elb-0d4e5f"When to Move Beyond Beanstalk
Beanstalk is an excellent starting point, but teams outgrow it:
- You need container orchestration: ECS or EKS gives finer control over containers, sidecar patterns, and blue/green deployments
- You need multiple services: Beanstalk environments model single-tier applications; microservices architectures fit ECS services better
- You need reproducible infrastructure: Beanstalk’s internal CloudFormation stacks are partially managed; consider AWS CDK or Terraform for full IaC control
- You need GitOps workflows: ECS with CodeDeploy or Kubernetes with ArgoCD provide richer deployment pipelines
The typical path is: Beanstalk for early-stage startup → ECS when the team grows and needs more control → EKS when Kubernetes features or portability become necessary.
Common Interview Questions
Q: Does Elastic Beanstalk cost anything? Beanstalk itself is free — you pay only for the underlying resources (EC2, load balancer, RDS). The same EC2 instances cost the same whether deployed by Beanstalk or manually. The premium is time savings, not dollars.
Q: What is the difference between All At Once and Rolling deployments? All At Once deploys to every instance simultaneously, causing brief downtime. Rolling deploys to a batch at a time, keeping remaining instances serving traffic. All At Once is faster; Rolling avoids downtime at the cost of temporary reduced capacity.
Q: How do you run database migrations with Beanstalk deployments?
Use a .ebextensions container command with leader_only: true to run the migration on one instance:
container_commands: 01-migrate: command: "python manage.py migrate" leader_only: trueQ: Can you run multiple applications in one Beanstalk environment? No, each environment runs a single application version. For multiple services, create separate environments or consider ECS with multiple services.