Aws

Elastic Beanstalk for Quick Deployments

Deploy Node.js applications to AWS Elastic Beanstalk with custom configurations, rolling deployments, and auto-scaling

Elastic Beanstalk for Quick Deployments

Overview

AWS Elastic Beanstalk is a platform-as-a-service (PaaS) that handles provisioning, load balancing, scaling, and monitoring so you can focus on writing code instead of managing infrastructure. It sits on top of core AWS services like EC2, ELB, Auto Scaling, and CloudWatch, giving you full access to those underlying resources while abstracting away the operational complexity. If you need to get a Node.js application into production on AWS without spending weeks learning CloudFormation or Terraform, Elastic Beanstalk is the fastest path from your terminal to a running, scalable deployment.

Prerequisites

Before you start, make sure you have the following in place:

  • An AWS account with IAM credentials configured
  • Node.js v18 or later installed locally
  • The AWS CLI installed and configured (aws configure)
  • The EB CLI installed (pip install awsebcli)
  • A basic understanding of Express.js and npm
  • Git installed (EB CLI uses git for deployments by default)

What Elastic Beanstalk Provides

Elastic Beanstalk is not a separate compute service. It is an orchestration layer. When you deploy an application, Beanstalk provisions real EC2 instances, creates an Elastic Load Balancer, sets up an Auto Scaling group, configures CloudWatch alarms, and wires everything together. You get a fully managed environment that you can still SSH into, customize with configuration files, and tune at every level.

The key resources Beanstalk manages for you:

  • EC2 instances running your application code
  • Elastic Load Balancer (ALB or Classic) distributing traffic
  • Auto Scaling group handling capacity changes
  • Security groups controlling network access
  • CloudWatch alarms monitoring health and performance
  • S3 bucket storing application versions
  • RDS instance (optional, can be attached or decoupled)

The important distinction from something like Lambda or Fargate is that you still have EC2 instances. You can SSH into them, install packages, inspect logs, and debug in ways that serverless platforms make difficult. But you do not have to manage AMIs, launch configurations, or deployment scripts yourself.

Platform Options for Node.js

Elastic Beanstalk supports multiple Node.js platform versions. When you create an environment, you select a platform branch. As of early 2026, the relevant options are:

Platform Branch Node.js Version Amazon Linux
Node.js 20 20.x Amazon Linux 2023
Node.js 18 18.x Amazon Linux 2023

Always use the latest Amazon Linux 2023-based platforms. The older Amazon Linux 2 platforms are being phased out. You can specify the platform explicitly:

eb create my-env --platform "Node.js 20 running on 64bit Amazon Linux 2023"

Or let the EB CLI prompt you during eb init.

EB CLI Setup and Usage

The EB CLI is the primary tool for working with Elastic Beanstalk. Install it with pip:

pip install awsebcli --upgrade

Verify the installation:

eb --version

The CLI commands you will use most often:

# Initialize a new EB application in your project directory
eb init

# Create an environment and deploy
eb create my-environment

# Deploy code changes to the running environment
eb deploy

# Open the application in a browser
eb open

# View recent logs
eb logs

# SSH into an instance
eb ssh

# View environment status
eb status

# Set environment variables
eb setenv KEY1=value1 KEY2=value2

# Terminate an environment (destroys all resources)
eb terminate my-environment

Initializing a Project

Run eb init in your project root. The CLI walks you through selecting a region, application name, and platform. It creates a .elasticbeanstalk/config.yml file:

branch-defaults:
  master:
    environment: my-app-prod
global:
  application_name: my-app
  default_platform: Node.js 20 running on 64bit Amazon Linux 2023
  default_region: us-west-2
  workspace_type: Application

Add .elasticbeanstalk/ to your .gitignore since it contains local configuration.

Application and Environment Creation

Elastic Beanstalk has two core concepts: applications and environments. An application is a logical container. An environment is a running instance of your code with specific configuration. You typically have multiple environments per application (dev, staging, production).

# Create a production environment with a load balancer
eb create prod-env --instance-type t3.small --scale 2

# Create a single-instance dev environment (no load balancer, cheaper)
eb create dev-env --single

The --single flag is important for development. It creates a single EC2 instance without a load balancer, which saves cost and simplifies debugging.

Customization with .ebextensions

The .ebextensions directory is where Elastic Beanstalk gets powerful. You place YAML configuration files (with a .config extension) in this directory, and Beanstalk processes them during deployment. The files are processed in alphabetical order, so prefix them with numbers.

Create the directory in your project root:

mkdir .ebextensions

Installing Packages

# .ebextensions/01-packages.config
packages:
  yum:
    git: []
    ImageMagick: []

Running Commands During Deployment

# .ebextensions/02-commands.config
commands:
  01_create_temp_dir:
    command: "mkdir -p /tmp/myapp/cache"
  02_set_permissions:
    command: "chmod 755 /tmp/myapp/cache"

container_commands:
  01_run_migrations:
    command: "node scripts/migrate.js"
    leader_only: true

The distinction between commands and container_commands matters. commands run before the application code is extracted. container_commands run after extraction but before the application starts. The leader_only flag ensures the command runs on only one instance during scaling events, which is critical for database migrations.

Custom Nginx Configuration

Elastic Beanstalk uses Nginx as a reverse proxy on Amazon Linux 2023 platforms. You can extend its configuration:

# .ebextensions/03-nginx.config
files:
  "/etc/nginx/conf.d/proxy.conf":
    mode: "000644"
    owner: root
    group: root
    content: |
      client_max_body_size 50M;
      proxy_read_timeout 300;
      proxy_connect_timeout 300;
      proxy_send_timeout 300;

Custom Log Files

# .ebextensions/04-logs.config
files:
  "/opt/elasticbeanstalk/tasks/taillogs.d/app-logs.conf":
    mode: "000644"
    owner: root
    group: root
    content: |
      /var/app/current/logs/*.log

This tells Beanstalk to include your custom log files when you run eb logs.

Environment Variables and Configuration

Never hardcode secrets or configuration values. Use environment variables:

# Set variables via CLI
eb setenv NODE_ENV=production DB_HOST=mydb.cluster.us-west-2.rds.amazonaws.com DB_PASSWORD=secret123 PORT=8080

You can also set them in .ebextensions:

# .ebextensions/05-env.config
option_settings:
  aws:elasticbeanstalk:application:environment:
    NODE_ENV: production
    PORT: 8080

Do not put secrets in .ebextensions files since those get committed to source control. Use eb setenv for sensitive values or pull them from AWS Secrets Manager at runtime.

In your Node.js application, access them normally:

var port = process.env.PORT || 8080;
var dbHost = process.env.DB_HOST;
var nodeEnv = process.env.NODE_ENV;

Elastic Beanstalk sets PORT to 8080 by default and expects your application to listen on that port. Do not change this unless you also update the Nginx proxy configuration.

Deployment Policies

Elastic Beanstalk supports several deployment strategies. Choosing the right one depends on your tolerance for downtime and the size of your fleet.

All at Once

Deploys to all instances simultaneously. Fast but causes downtime.

# .ebextensions/06-deployment.config
option_settings:
  aws:elasticbeanstalk:command:
    DeploymentPolicy: AllAtOnce

Use this for development environments where downtime does not matter.

Rolling

Deploys to batches of instances. The remaining instances continue serving traffic.

option_settings:
  aws:elasticbeanstalk:command:
    DeploymentPolicy: Rolling
    BatchSize: 30
    BatchSizeType: Percentage

This deploys to 30% of instances at a time. During deployment, your fleet runs a mix of old and new code. Your application must handle this gracefully.

Rolling with Additional Batch

Like rolling, but launches a fresh batch of instances first so you never drop below full capacity.

option_settings:
  aws:elasticbeanstalk:command:
    DeploymentPolicy: RollingWithAdditionalBatch
    BatchSize: 1
    BatchSizeType: Fixed

Immutable

Launches an entirely new set of instances with the new code, health-checks them, then swaps them into the Auto Scaling group and terminates the old instances.

option_settings:
  aws:elasticbeanstalk:command:
    DeploymentPolicy: Immutable

This is the safest option. If the new instances fail health checks, Beanstalk rolls back automatically. It is slower and costs more (temporarily doubles your fleet), but it is what I use for production.

Blue-Green Deployment

Blue-green is not a built-in deployment policy. You achieve it by creating a second environment and swapping CNAMEs:

# Create a "green" environment
eb create prod-green --cfg saved-prod-config

# Deploy new version to green
eb deploy prod-green

# Test green environment
curl https://prod-green.us-west-2.elasticbeanstalk.com/health

# Swap URLs between blue and green
eb swap prod-blue --destination_name prod-green

The CNAME swap is nearly instantaneous and gives you the safest rollback path. If something goes wrong, swap back.

Procfile and Platform Hooks

Procfile

The Procfile tells Beanstalk how to start your application. Create it in your project root:

web: node app.js

Without a Procfile, Beanstalk runs npm start. I prefer being explicit with a Procfile because it removes ambiguity and starts the process directly without npm overhead.

You can also run background workers:

web: node app.js
worker: node worker.js

Platform Hooks

Platform hooks run scripts at specific points in the deployment lifecycle. They are more powerful than .ebextensions commands for complex scenarios.

# Create hook directories
mkdir -p .platform/hooks/predeploy
mkdir -p .platform/hooks/postdeploy
#!/bin/bash
# .platform/hooks/predeploy/01_install_deps.sh
cd /var/app/staging
npm ci --production
#!/bin/bash
# .platform/hooks/postdeploy/01_run_migrations.sh
cd /var/app/current
node scripts/migrate.js

Make sure hook scripts are executable:

chmod +x .platform/hooks/predeploy/01_install_deps.sh
chmod +x .platform/hooks/postdeploy/01_run_migrations.sh

Log Access and Monitoring

Viewing Logs

# Request last 100 lines from all instances
eb logs

# Request full logs bundled as a zip
eb logs --all

# Stream logs in real-time
eb logs --stream

Logs are also stored in CloudWatch if you enable it:

# .ebextensions/07-cloudwatch.config
option_settings:
  aws:elasticbeanstalk:cloudwatch:logs:
    StreamLogs: true
    DeleteOnTerminate: false
    RetentionInDays: 30

Health Monitoring

Beanstalk checks the health of your application by making HTTP requests to the root path (/) by default. Configure a dedicated health endpoint:

option_settings:
  aws:elasticbeanstalk:application:
    Application Healthcheck URL: /health

In your Express app:

app.get("/health", function(req, res) {
  res.status(200).json({
    status: "healthy",
    uptime: process.uptime(),
    timestamp: new Date().toISOString()
  });
});

Enable enhanced health reporting for more detailed metrics:

option_settings:
  aws:elasticbeanstalk:healthreporting:system:
    SystemType: enhanced

Scaling Configuration

Auto Scaling is where Elastic Beanstalk earns its keep. Configure scaling based on CPU, network, or request count:

# .ebextensions/08-scaling.config
option_settings:
  aws:autoscaling:asg:
    MinSize: 2
    MaxSize: 8

  aws:autoscaling:trigger:
    MeasureName: CPUUtilization
    Statistic: Average
    Unit: Percent
    UpperThreshold: 70
    LowerThreshold: 30
    UpperBreachScaleIncrement: 2
    LowerBreachScaleIncrement: -1
    BreachDuration: 5
    Period: 5

  aws:autoscaling:launchconfiguration:
    InstanceType: t3.small
    SecurityGroups: sg-xxxxxxxx

This configuration scales up by 2 instances when average CPU exceeds 70% for 5 minutes, and scales down by 1 instance when CPU drops below 30%.

For production workloads, I recommend a minimum of 2 instances across different Availability Zones for high availability.

Load Balancer Setup

By default, Beanstalk creates an Application Load Balancer (ALB). Configure it for your needs:

# .ebextensions/09-alb.config
option_settings:
  aws:elasticbeanstalk:environment:
    LoadBalancerType: application

  aws:elbv2:listener:443:
    ListenerEnabled: true
    Protocol: HTTPS
    SSLCertificateArns: arn:aws:acm:us-west-2:123456789:certificate/abc-123

  aws:elbv2:listener:default:
    ListenerEnabled: true
    Protocol: HTTP

  aws:elbv2:listener:80:
    DefaultProcess: default
    ListenerEnabled: true
    Protocol: HTTP
    Rules: redirect-http

  aws:elbv2:listenerrule:redirect-http:
    PathPatterns: /*
    Process: default
    Priority: 1

Sticky Sessions

If your application uses sessions, enable sticky sessions on the load balancer:

option_settings:
  aws:elasticbeanstalk:environment:process:default:
    StickinessEnabled: true
    StickinessLBCookieDuration: 86400

A better approach is to use Redis or DynamoDB for session storage so your application is stateless and can scale freely.

Custom Domain and SSL

SSL Certificate

Request a free SSL certificate through AWS Certificate Manager (ACM):

aws acm request-certificate \
  --domain-name myapp.example.com \
  --validation-method DNS \
  --region us-west-2

Validate the certificate via DNS, then reference it in your load balancer configuration as shown above.

Custom Domain

Point your domain to the Elastic Beanstalk environment using a CNAME record or, if using Route 53, an alias record:

aws route53 change-resource-record-sets \
  --hosted-zone-id Z1234567890 \
  --change-batch '{
    "Changes": [{
      "Action": "UPSERT",
      "ResourceRecordSet": {
        "Name": "myapp.example.com",
        "Type": "CNAME",
        "TTL": 300,
        "ResourceRecords": [{"Value": "my-env.us-west-2.elasticbeanstalk.com"}]
      }
    }]
  }'

HTTPS Redirect

Force all HTTP traffic to HTTPS with an Nginx configuration extension:

# .ebextensions/10-https-redirect.config
files:
  "/etc/nginx/conf.d/https_redirect.conf":
    mode: "000644"
    owner: root
    group: root
    content: |
      server {
        listen 80;
        if ($http_x_forwarded_proto = "http") {
          return 301 https://$host$request_uri;
        }
      }

Note the use of $http_x_forwarded_proto instead of $scheme. Since Nginx sits behind the load balancer, the connection between the ALB and Nginx is always HTTP. You need the forwarded header to determine the original protocol.

Docker on Elastic Beanstalk

Elastic Beanstalk supports Docker deployments, which gives you full control over the runtime environment. This is useful when you need specific system libraries, a particular Node.js version, or want to keep your deployment environment identical to local development.

Create a Dockerfile in your project root:

FROM node:20-alpine

WORKDIR /app

COPY package*.json ./
RUN npm ci --production

COPY . .

EXPOSE 8080

CMD ["node", "app.js"]

Beanstalk detects the Dockerfile and builds the image on the instance. For faster deployments, push your image to ECR and reference it:

{
  "AWSEBDockerrunVersion": "1",
  "Image": {
    "Name": "123456789.dkr.ecr.us-west-2.amazonaws.com/my-app:latest",
    "Update": "true"
  },
  "Ports": [
    {
      "ContainerPort": 8080,
      "HostPort": 8080
    }
  ]
}

Save this as Dockerrun.aws.json in your project root.

Migration Path to ECS

Elastic Beanstalk is a great starting point, but as your application grows you may want to migrate to ECS (Elastic Container Service) for more control over container orchestration. The migration path looks like this:

  1. Start with Beanstalk Docker platform - This gets you containerized early
  2. Move to ECR - Push images to Elastic Container Registry instead of building on instances
  3. Create an ECS task definition from your Dockerfile
  4. Set up an ECS service with an ALB (you can reuse your existing one)
  5. Shift traffic gradually using weighted target groups

The Docker-first approach on Beanstalk makes this transition smoother because your application is already containerized. The main work is defining the ECS task definition, service, and cluster configuration.

# Push your Docker image to ECR
aws ecr get-login-password --region us-west-2 | docker login --username AWS --password-stdin 123456789.dkr.ecr.us-west-2.amazonaws.com

docker build -t my-app .
docker tag my-app:latest 123456789.dkr.ecr.us-west-2.amazonaws.com/my-app:latest
docker push 123456789.dkr.ecr.us-west-2.amazonaws.com/my-app:latest

# Create ECS cluster
aws ecs create-cluster --cluster-name my-app-cluster

# Register task definition
aws ecs register-task-definition --cli-input-json file://task-definition.json

Complete Working Example

Let us build and deploy a production-ready Express application to Elastic Beanstalk with custom configuration, rolling deployments, and auto-scaling.

Project Structure

my-app/
  .ebextensions/
    01-packages.config
    02-env.config
    03-deployment.config
    04-scaling.config
    05-logs.config
  .platform/
    hooks/
      postdeploy/
        01_cleanup.sh
  app.js
  package.json
  Procfile
  .ebignore
  .gitignore

package.json

{
  "name": "my-beanstalk-app",
  "version": "1.0.0",
  "description": "Production Express app on Elastic Beanstalk",
  "main": "app.js",
  "scripts": {
    "start": "node app.js"
  },
  "engines": {
    "node": "20.x"
  },
  "dependencies": {
    "express": "^4.18.2",
    "compression": "^1.7.4",
    "helmet": "^7.1.0",
    "morgan": "^1.10.0",
    "cors": "^2.8.5"
  }
}

app.js

var express = require("express");
var compression = require("compression");
var helmet = require("helmet");
var morgan = require("morgan");
var cors = require("cors");
var os = require("os");

var app = express();
var port = process.env.PORT || 8080;

// Middleware
app.use(helmet());
app.use(compression());
app.use(cors());
app.use(morgan("combined"));
app.use(express.json());
app.use(express.urlencoded({ extended: true }));

// Health check endpoint
app.get("/health", function(req, res) {
  res.status(200).json({
    status: "healthy",
    environment: process.env.NODE_ENV || "development",
    hostname: os.hostname(),
    uptime: Math.floor(process.uptime()),
    memory: {
      used: Math.round(process.memoryUsage().heapUsed / 1024 / 1024) + "MB",
      total: Math.round(process.memoryUsage().heapTotal / 1024 / 1024) + "MB"
    },
    timestamp: new Date().toISOString()
  });
});

// API routes
app.get("/", function(req, res) {
  res.json({
    message: "Welcome to the API",
    version: "1.0.0",
    docs: "/api/docs"
  });
});

app.get("/api/items", function(req, res) {
  var page = parseInt(req.query.page) || 1;
  var limit = parseInt(req.query.limit) || 20;

  // Simulated database query
  var items = [];
  for (var i = 0; i < limit; i++) {
    items.push({
      id: (page - 1) * limit + i + 1,
      name: "Item " + ((page - 1) * limit + i + 1),
      createdAt: new Date().toISOString()
    });
  }

  res.json({
    data: items,
    pagination: {
      page: page,
      limit: limit,
      total: 100
    }
  });
});

app.post("/api/items", function(req, res) {
  var name = req.body.name;

  if (!name) {
    return res.status(400).json({ error: "Name is required" });
  }

  res.status(201).json({
    id: Date.now(),
    name: name,
    createdAt: new Date().toISOString()
  });
});

// Error handling
app.use(function(req, res) {
  res.status(404).json({ error: "Not found" });
});

app.use(function(err, req, res, next) {
  console.error("Unhandled error:", err.stack);
  res.status(500).json({ error: "Internal server error" });
});

// Start server
app.listen(port, function() {
  console.log("Server running on port " + port);
  console.log("Environment: " + (process.env.NODE_ENV || "development"));
  console.log("PID: " + process.pid);
});

// Graceful shutdown
process.on("SIGTERM", function() {
  console.log("SIGTERM received. Shutting down gracefully...");
  process.exit(0);
});

Procfile

web: node app.js

.ebignore

The .ebignore file works like .gitignore but specifically for EB deployments. This controls what gets uploaded:

.git
node_modules
.env
*.log
test/
coverage/
.vscode/
.idea/

.ebextensions/01-packages.config

packages:
  yum:
    git: []

.ebextensions/02-env.config

option_settings:
  aws:elasticbeanstalk:application:environment:
    NODE_ENV: production
    PORT: 8080

  aws:elasticbeanstalk:application:
    Application Healthcheck URL: /health

.ebextensions/03-deployment.config

option_settings:
  aws:elasticbeanstalk:command:
    DeploymentPolicy: Rolling
    BatchSize: 50
    BatchSizeType: Percentage
    Timeout: 600

  aws:elasticbeanstalk:healthreporting:system:
    SystemType: enhanced

.ebextensions/04-scaling.config

option_settings:
  aws:autoscaling:asg:
    MinSize: 2
    MaxSize: 6

  aws:autoscaling:trigger:
    MeasureName: CPUUtilization
    Statistic: Average
    Unit: Percent
    UpperThreshold: 70
    LowerThreshold: 25
    UpperBreachScaleIncrement: 2
    LowerBreachScaleIncrement: -1
    BreachDuration: 5
    Period: 5

  aws:autoscaling:launchconfiguration:
    InstanceType: t3.small
    RootVolumeType: gp3
    RootVolumeSize: 20

  aws:elbv2:listener:default:
    ListenerEnabled: true
    Protocol: HTTP

.ebextensions/05-logs.config

option_settings:
  aws:elasticbeanstalk:cloudwatch:logs:
    StreamLogs: true
    DeleteOnTerminate: false
    RetentionInDays: 14

Deploy It

# Initialize the EB application
eb init my-beanstalk-app --platform "Node.js 20 running on 64bit Amazon Linux 2023" --region us-west-2

# Create the environment and deploy
eb create prod --scale 2 --instance-type t3.small

# Wait for environment to go green, then verify
eb status
eb open

# Future deployments
eb deploy

Common Issues and Troubleshooting

1. Application Fails to Start - Port Binding Error

ERROR   Engine execution has encountered an error.
[ERROR] An error occurred during execution of command [app-deploy] -
  [Stage 0: Application] - [Step 0: StageApplication]. Stop running the command.
  Error: unable to execute command: /bin/sh -c node app.js
  Error: listen EADDRINUSE :::8080

This happens when your application tries to bind to a port already in use, or when a previous deployment left a zombie process. Fix: ensure your app reads process.env.PORT and handles SIGTERM for graceful shutdown. If the problem persists, restart the environment:

eb restart

2. npm Install Fails Due to Node Version Mismatch

npm WARN EBADENGINE Unsupported engine {
  package: '[email protected]',
  required: { node: '>=20.0.0' },
  current: { node: 'v18.18.0' }
}
npm ERR! engine Unsupported engine

Your package.json engines field specifies a Node.js version that does not match the platform. Either update your engines field or select the correct platform:

eb config
# Change the platform to match your required Node.js version

3. Health Check Returns 502 During Deployment

WARN  Environment health has transitioned from Ok to Degraded.
  50.0 % of the requests are failing with HTTP 5xx.
ERROR Instance i-0abc123def456 has been terminated.
  ELB health check failed: 502 Bad Gateway

Your application takes too long to start, and the health check times out before it is ready. Increase the health check timeout and add a startup delay:

option_settings:
  aws:elasticbeanstalk:environment:process:default:
    HealthCheckPath: /health
    HealthCheckInterval: 30
    HealthyThresholdCount: 3
    UnhealthyThresholdCount: 5

Also verify your app actually responds on the /health path and does not crash during startup.

4. Deployment Stuck in "Updating" State

INFO  Environment update is starting.
WARN  Environment health has transitioned from Ok to Info.
  Application update is in progress.
  ...
  (no further output for 30+ minutes)

This usually happens with immutable deployments when the new instances fail health checks but do not fail hard enough to trigger a rollback. Check the instance logs:

eb logs --all

Look in /var/log/eb-engine.log and /var/log/web.stdout.log for the root cause. If the environment is truly stuck, abort the update:

aws elasticbeanstalk abort-environment-update --environment-name prod

5. .ebextensions Config File Not Picked Up

WARN  The configuration file .ebextensions/01-packages.config in application version
  contains invalid YAML or JSON. Skipping file.

YAML is extremely sensitive to formatting. Use spaces, not tabs. Use a YAML validator before committing. Also verify the file extension is .config, not .yaml or .yml.

6. Environment Variables Not Available at Build Time

If you reference environment variables during npm install or npm run build, they will not be available because Beanstalk sets them after the application is staged. Move build-time configuration to .ebextensions container commands instead:

container_commands:
  01_build:
    command: "export API_URL=https://api.example.com && npm run build"

Best Practices

  • Use immutable deployments for production. The extra cost during deployment is worth the automatic rollback safety net. Reserve all-at-once for dev environments only.

  • Decouple your RDS database from Elastic Beanstalk. If you create an RDS instance through Beanstalk, it gets deleted when you terminate the environment. Create RDS separately and pass the connection string as an environment variable.

  • Set up a .ebignore file. Without it, EB CLI uses .gitignore, which might exclude files you actually need deployed (like .env.example templates). The .ebignore file gives you explicit control over what gets uploaded.

  • Enable enhanced health reporting. Basic health checks only verify that the instance is reachable. Enhanced health reporting monitors HTTP response codes, request latency, and instance metrics to give you a real picture of application health.

  • Use npm ci instead of npm install in production. It is faster, deterministic, and fails if package-lock.json is out of sync with package.json. Beanstalk runs npm install by default, but you can override this with a Procfile or platform hook.

  • Always configure graceful shutdown. Handle SIGTERM in your application to close database connections and finish in-flight requests before exiting. Beanstalk sends SIGTERM before killing processes during deployments.

  • Set the engines field in package.json. This documents which Node.js version your app requires and catches platform mismatches early.

  • Use saved configurations for environment consistency. Save your production configuration and use it to create staging and pre-production environments that are identical:

eb config save prod --cfg production-config
eb create staging --cfg production-config
  • Monitor deployment history. Every deployment creates an application version in S3. Review them periodically and clean up old versions to avoid hitting the 1000 version limit:
aws elasticbeanstalk describe-application-versions --application-name my-app
  • Tag your environments. Use tags for cost allocation and resource organization. This becomes critical when you have multiple applications and environments:
eb tags --add Project=my-app,Team=backend,Environment=production

References

Powered by Contentful