DEV Community

Ezekiel Umesi
Ezekiel Umesi

Posted on

Getting started: Deploy your first app with ECS Express Mode

As an engineer, if you have tried to deploy a container on AWS the traditional way, you must know the feeling of getting a single app online with Amazon ECS. You'd find yourself clicking through cluster setups, several task definitions, security groups, and load balancer configurations, each with its own settings, just to ensure that everything works. For a first timer, this can be a lot to setup.

The introduction of ECS Express Mode is AWS's answer to that. Here, it collapses all of that setup into three things to get started: A container image, a task execution role, and an infrastructure role, so that once you hand it your image, it provisions and wires up the rest for you.

It is important to note that Express Mode is the successor to AWS App Runner. This is because AWS has decided to close App Runner to use customers starting April 30, 2026, and now, they recommend Amazon ECS Express as the migration path because it keeps App Runner's simplicity while providing full ECS features. So if you are considering building new applications today, Express Mode is the path you should be pointing to.

At the end of this article, you'll have taken your own container image, and turned it into a live, HTTPS-secured URL. Let's build.

What you'll build

Power Snapshot

We'll deploy Power Snapshot NG — a tiny web service that fetches official Nigeria electricity indicators from the World Bank Open Data API and displays them in the browser. Type nothing complicated: open the URL and you see real national stats — electricity access as a percentage of the population, consumption per capita, and renewable share of generation.

It's deliberately compact (one container, one port, two API routes), so nothing distracts from the deployment. But it's a step beyond the usual static "hello world": you get a live UI, a working backend, and data pulled from the outside world. If you work with data, it's a practical hint of what containers unlock — and an honest one. Unlike the UK, Nigeria doesn't offer a free public live grid API, so we use the latest published national indicators rather than minute-by-minute carbon intensity.

Under the hood, the image bundles a lightweight HTML frontend and a Node.js/Express API into a single container on port 80. Express Mode handles the HTTPS URL, load balancer, and scaling. Your job is build, push, deploy.

The sample app lives in the express-mode/ folder of the repo. Clone it, follow along, and swap in your own image later if you prefer — every step below works the same.

What Express Mode does for you

Think of Express Mode as a production-ready default layer on top of ECS. When you create an Express Mode service, AWS automatically provisions:

  • An ECS service running on AWS Fargate
  • An Application Load Balancer with HTTPS and SSL/TLS termination
  • Auto scaling policies (CPU-based by default)
  • CloudWatch logging and monitoring
  • Security groups and networking in your default VPC
  • A unique HTTPS URL on the *.ecs.<region>.on.aws domain

You don't configure any of that manually on day one. You provide the image and two IAM roles; Express Mode wires the rest.

Prerequisites

Before you start, make sure you have:

  • An AWS account with permissions to use ECS, ECR, IAM, and CloudWatch
  • The AWS CLI v2 installed and configured (aws configure)
  • Docker Desktop installed and running locally
  • A terminal open in the express-mode/ folder of the sample repo

You'll also need a container image stored in Amazon ECR — Step 2 creates and pushes that. Express Mode does not build from source the way App Runner could; you bring a ready-made image.

Step 1 — Build your container image

Get the sample app

Clone the repository and navigate into the Express Mode sample directory:

git clone https://github.com/obusorezekiel/power-snapshot-ng
cd power-snapshot-ng
Enter fullscreen mode Exit fullscreen mode

The application is a Node.js server (server.js) that serves static content from the public/ folder and exposes two API routes:

Route Purpose
/api/health Returns { "status": "ok" }; used by the load balancer health check.
/api/energy Fetches Nigeria electricity statistics from the World Bank API.

The Dockerfile, line by line

Instruction Description
FROM node:20-alpine Starts from a lightweight Linux image with Node.js 20.
WORKDIR /app Sets the working directory inside the container.
COPY package*.json ./ Copies dependency definitions.
RUN npm install --omit=dev Installs production dependencies (cached layer).
COPY server.js ./ Copies the application server code.
COPY public ./public Copies static assets.
ENV PORT=80 Sets the application port environment variable.
EXPOSE 80 Informs Docker that the container listens on port 80.
CMD ["node", "server.js"] Starts the web server on launch.

Build and test locally

  1. Build the image:
docker build -t power-snapshot-ng .
Enter fullscreen mode Exit fullscreen mode
  1. Run the container locally (mapping port 8080):
docker run -p 8080:80 --name power-test power-snapshot-ng
Enter fullscreen mode Exit fullscreen mode
  1. Verify the deployment by visiting http://localhost:8080. You should see the Nigeria electricity indicators page.

  2. Confirm the health endpoint:

curl http://localhost:8080/api/health
Enter fullscreen mode Exit fullscreen mode

Expected response: {"status":"ok"}

  1. Stop and remove the test container:
docker stop power-test
docker rm power-test
Enter fullscreen mode Exit fullscreen mode

Testing locally ensures your container configuration is correct before deploying to AWS, saving significant time during the ECS deployment process.

Local Build

Step 2 — Push the image to ECR

Amazon ECS pulls container images from a registry. We'll use Amazon ECR — AWS's private Docker registry.

Set Environment Variables

First, define your region and AWS Account ID:

AWS_REGION = "us-east-1"
AWS_ACCOUNT_ID = aws sts get-caller-identity --query Account --output text
Enter fullscreen mode Exit fullscreen mode

Create the Repository

Create the repository (skip this step if it already exists):

aws ecr create-repository --repository-name power-snapshot-ng --region $AWS_REGION
Enter fullscreen mode Exit fullscreen mode

Authenticate Docker

Authenticate your local Docker client to your ECR registry:

aws ecr get-login-password --region $AWS_REGION | docker login --username AWS --password-stdin "$AWS_ACCOUNT_ID.dkr.ecr.$AWS_REGION.amazonaws.com"
Enter fullscreen mode Exit fullscreen mode

Docker Auth

Tag and Push

Tag your local image and push it to ECR:

docker tag power-snapshot-ng:latest "$AWS_ACCOUNT_ID.dkr.ecr.$AWS_REGION.amazonaws.com/power-snapshot-ng:latest"
docker push "$AWS_ACCOUNT_ID.dkr.ecr.$AWS_REGION.amazonaws.com/power-snapshot-ng:latest"
Enter fullscreen mode Exit fullscreen mode

Verification

Verify in the console: open Amazon ECR, select power-snapshot-ng, and confirm the latest image is listed.

Note: Save your full image URI — you'll paste it into Express Mode in the next section: <ACCOUNT_ID>.dkr.ecr.<REGION>.amazonaws.com/power-snapshot-ng:latest

Step 3 — Create the two IAM roles

Express Mode requires two specific IAM roles to function.

Role Purpose Managed Policy
Task execution role Lets ECS pull your image from ECR and write logs to CloudWatch. AmazonECSTaskExecutionRolePolicy
Infrastructure role Lets Express Mode create the ALB, target groups, security groups, and scaling policies on your behalf. AmazonECSInfrastructureRolePolicyForExpressServices

The easy path

When you create the Express Mode service in the AWS console, simply choose Create new role from each role dropdown. AWS will automatically attach the correct policies for you.

Manual creation

If you prefer to create them manually:

Task Execution Role:

  1. Navigate to IAM → Roles → Create role
  2. Select Elastic Container Service → Elastic Container Service Task
  3. Attach AmazonECSTaskExecutionRolePolicy
  4. Name it: ecsTaskExecutionRole

Infrastructure Role:

  1. Navigate to IAM → Roles → Create role
  2. Select Elastic Container Service
  3. Attach AmazonECSInfrastructureRolePolicyForExpressServices
  4. Name it: ecsInfrastructureRoleForExpressServices

Note: For a simple app like this, the managed policies cover everything. No custom inline policies are needed.

Step 4 — Deploy with Express Mode

This is the payoff. Follow these steps to get your container live.

Console walkthrough

  1. Open the Amazon ECS console
  2. In the left navigation, choose Express mode
  3. Choose Create
  4. Fill in the general configuration parameters:
Field Value for this app
Container image URI 353928175117.dkr.ecr.us-east-1.amazonaws.com/power-snapshot-ng:latest
Task execution role ecsTaskExecutionRole
Infrastructure role ecsInfrastructureRoleForExpressServices
Service name power-snapshot-ng
  1. Expand Additional configurations and set:
Field Value Note
Container port 80 The app listens on port 80 inside the container.
Health check path /api/health Express Mode defaults to /ping — this app uses /api/health.
  1. Leave other settings as default (1 vCPU, 2 GB RAM, CPU-based auto scaling) and choose Create

Watch the provisioning progress in the Resources tab. AWS is wiring up your cluster, ALB, and URL.

When the status is Running, copy your new URL (e.g., https://po-5195b9c4136c4ef882cf7743809f69cd.ecs.us-east-1.on.aws) and open it.

Congratulations! You've successfully deployed a containerized app with a secured HTTPS endpoint.

CLI alternative

If you prefer the command line, use the following command to perform the same deployment:

aws ecs create-express-gateway-service \
  --region $AWS_REGION \
  --service-name power-snapshot-ng \
  --execution-role-arn "arn:aws:iam::${AWS_ACCOUNT_ID}:role/ecsTaskExecutionRole" \
  --infrastructure-role-arn "arn:aws:iam::${AWS_ACCOUNT_ID}:role/ecsInfrastructureRoleForExpressServices" \
  --primary-container "image=${AWS_ACCOUNT_ID}.dkr.ecr.${AWS_REGION}.amazonaws.com/power-snapshot-ng:latest,containerPort=80" \
  --health-check-path "/api/health" \
  --monitor-resources
Enter fullscreen mode Exit fullscreen mode

What went wrong — troubleshooting

This table summarizes common failures beginners encounter when deploying the Power Snapshot NG app.

Issue Symptom Cause Fix
Health Check Fail Tasks restart; service stuck in deploy loop. Default path /ping is used instead of /api/health. Set Health check path to /api/health.
502 Bad Gateway URL loads but returns 502 error. Port mismatch between ALB and container. Set Container port to 80.
Missing Data UI loads but shows "Loading..." or error. Backend cannot reach World Bank API. Check CloudWatch Logs for timeouts.
Pull Error Tasks fail with CannotPullContainerError. Task role missing ECR permissions. Attach AmazonECSTaskExecutionRolePolicy.

Peek under the hood

After your service is running, open these in the console. Express Mode didn't hide anything — it just created it for you.

Resource Where to find it What to notice
ECS cluster ECS → Clusters A cluster created/reused for your service.
ECS service ECS → Services Desired count and deployment status.
Task definition ECS → Task definitions CPU/Memory and container image URI.
Application Load Balancer ECS → Load Balancers Internet-facing ALB with HTTPS.
Target group ECS → Target Groups Health check path and port 80 config.
CloudWatch log group CloudWatch → Log groups Logs from your Node process.

These are standard ECS resources. You can edit the task definition, adjust auto scaling, attach a custom domain, or add environment variables — the same way you would with any ECS service. Express Mode is a starting point, not a cage.

Cleanup

Don't skip this. Idle AWS resources charge by the hour, and an ALB left running overnight is an unpleasant surprise.

  1. Delete the ECS service: Navigate to ECS → Express mode → Select power-snapshot-ng → Delete
  2. Wait for decommissioning: Ensure the service disappears from the console list before proceeding
  3. Delete the ECR repository: ECR → power-snapshot-ng → Delete repository (check "force delete")
  4. Remove the Load Balancer: Verify the shared ALB is removed under EC2 → Load Balancers
  5. Purge Log Groups: Optionally delete orphaned CloudWatch log groups manually

Note: If you deployed multiple Express Mode services, they may share one ALB — deleting one service won't always delete the load balancer until all services using it are gone.

Conclusion

You built a Docker image locally, pushed it to ECR, created two IAM roles, and deployed it to Amazon ECS Express Mode — ending with a live HTTPS URL serving a real data app. No cluster configuration spreadsheets. No manual ALB wiring. Three inputs, one deployment flow.

As of mid-2026, ECS Express Mode is available in all AWS regions where ECS and Fargate are supported. Console layout and label names may change — match what you see in AWS against the concepts described here.

Top comments (0)