AWS App Runner stopped taking new sign-ups on April 30, 2026. If you had a project planned around it, or you are running existing App Runner services and watching the writing on the wall, AWS has already told you where to go next: Amazon ECS Express Mode. It is not a rebrand and it is not a stopgap. AWS calls it out by name on the App Runner product page itself, right next to the sign-up cutoff notice, as the recommended way to deploy and run containerized applications going forward.
This tutorial walks through deploying a containerized app on Amazon ECS Express Mode from a cold start in August 2026: what changed, why AWS moved App Runner to maintenance, how Express Mode is different from wiring up ECS and Fargate by hand, and the exact console and CLI steps to get a service live behind a load balancer. If you already run App Runner in production, there is a dedicated migration section near the end that covers cutting over DNS without downtime.
Don't miss new tech stories on Google
Add Tech Insider once in the Google app and our stories appear in your news suggestions.
Why AWS App Runner Is No Longer the Default Choice
On March 31, 2026, AWS published a service availability update listing AWS App Runner among the services moving into maintenance. The notice states plainly: “Services moving to maintenance will no longer be accessible to new customers starting April 30, 2026.” The App Runner documentation repeats the same message in the product’s own availability-change page: “AWS App Runner is no longer open to new customers. Existing customers can continue to use the service as normal.”
Nothing shuts off for people already running App Runner services. AWS says existing customers keep full access, can still create new services under existing accounts, and will keep getting security patches. What stops is net-new feature work. No new runtimes, no new regions, no new capabilities land on App Runner going forward. For a platform-as-a-service product, that is functionally the end of its growth curve, even if the lights stay on for years.
AWS did not leave a gap. The App Runner page now reads: “For deploying and running containerized applications, we recommend Amazon ECS Express Mode, a new capability in Amazon ECS.” That is about as direct as a cloud vendor’s migration guidance gets, and it is the reason this tutorial exists. ECS Express Mode picked up steam through 2026: AWS announced it broadly in mid-2026, expanded it to AWS GovCloud (US-East) and AWS GovCloud (US-West) on June 15, 2026, and added support for custom task definitions on July 1, 2026, closing one of the earlier gaps between App Runner’s simplicity and ECS’s flexibility.
What Amazon ECS Express Mode Actually Is
Regular Amazon ECS on Fargate asks you to assemble several pieces yourself: a cluster, a task definition, a service, a load balancer with target groups and listeners, security groups, an auto scaling policy, and a CloudWatch log group. Every one of those is a separate resource with its own configuration surface. That flexibility is exactly why ECS has been AWS’s workhorse container orchestrator for a decade, but it also means a first deployment can take an afternoon even for an experienced engineer.
ECS Express Mode collapses that setup into a single, opinionated service definition. You give it a container image, a CPU and memory size, a port, and a handful of environment variables, and Express Mode provisions the ECS cluster, the Fargate service, the Application Load Balancer, the security groups, the auto scaling configuration, and the CloudWatch logging on your behalf. It is, in practical terms, an App Runner-shaped front door bolted onto standard ECS and Fargate primitives underneath, rather than a separate managed runtime with its own billing engine.
That distinction matters for how you think about the service. App Runner was a black box: you never saw the ECS tasks, load balancers, or scaling policies it created behind the scenes. Express Mode is closer to a scaffold. It creates real, visible ECS and ALB resources in your account. You can inspect them in the ECS console, and after the July 2026 update, you can hand it a custom task definition instead of accepting the defaults, which gives you an escape hatch App Runner never offered.
Prerequisites
Get these in place before starting the walkthrough. None of this is exotic if you have touched ECS or Fargate before, but skipping a step here is the most common reason a first Express Mode deployment stalls at the health check stage.
- An active AWS account with permissions for ECS, EC2 (for VPC/ALB/security groups), IAM, and CloudWatch Logs. Administrator access is easiest for a first run; scope it down afterward.
- AWS CLI version 2 installed and configured (
aws --versionshould report 2.x). Version 1 is still documented for legacy reference, but AWS recommends v2 for all new work in 2026. - Docker Desktop or the Docker Engine (20.10 or newer) installed locally to build and push a container image.
- An Amazon ECR repository, or a public image (Docker Hub or another public registry) you are authorized to deploy. Express Mode is image-based: none of the current documentation or migration guides show a “deploy from GitHub source” option the way early App Runner offered, so plan on shipping a built image.
- A VPC with at least two subnets in different Availability Zones. The default VPC in most accounts already satisfies this; Express Mode needs at least two subnets to place the Application Load Balancer.
- A registered domain if you want a custom domain on the finished service (optional for this tutorial, covered in Step 10).
- Roughly 90 minutes for the full walkthrough, including the ~10-15 minutes ECS typically takes to pull an image, start tasks, and pass initial ALB health checks.
Step 1: Confirm Your AWS CLI and Region Setup
Start by confirming your CLI version and default region. ECS Express Mode is a console-and-API-level capability layered on ECS, so anything that works for standard ECS CLI calls in your account will work here too.
aws --version
# aws-cli/2.x.x Python/3.x.x Linux/x86_64
aws configure get region
# us-east-1
aws sts get-caller-identity
# {
# "UserId": "AIDAEXAMPLE123456789",
# "Account": "123456789012",
# "Arn": "arn:aws:iam::123456789012:user/your-user"
# }
If aws sts get-caller-identity fails, your credentials are not configured correctly and nothing downstream will work. Fix that first with aws configure before moving on.
Step 2: Build and Push a Container Image to Amazon ECR
Express Mode needs an image to deploy. If you already have one in ECR or a public registry, skip to Step 3. Otherwise, here is a minimal Node.js example you can substitute with your own app.
# Dockerfile
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --omit=dev
COPY . .
EXPOSE 8080
CMD ["node", "server.js"]
Create the ECR repository, authenticate Docker against it, then build, tag, and push:
aws ecr create-repository --repository-name my-express-app --region us-east-1
aws ecr get-login-password --region us-east-1 | \
docker login --username AWS --password-stdin \
123456789012.dkr.ecr.us-east-1.amazonaws.com
docker build -t my-express-app .
docker tag my-express-app:latest \
123456789012.dkr.ecr.us-east-1.amazonaws.com/my-express-app:latest
docker push 123456789012.dkr.ecr.us-east-1.amazonaws.com/my-express-app:latest
Replace 123456789012 with your own account ID throughout this tutorial. Confirm the push succeeded before continuing:
aws ecr describe-images --repository-name my-express-app --region us-east-1
Step 3: Open ECS Express Mode in the Console
Sign in to the AWS Management Console and open the Amazon ECS service. In the ECS console navigation, Express Mode surfaces as a distinct, simplified creation path alongside standard cluster and service creation, mirroring the “create a service” flow App Runner users are used to. Choose the Express Mode entry point rather than the classic “create cluster, then create service” sequence.
This is the point where Express Mode’s value shows up immediately: instead of a multi-page wizard for cluster capacity providers, network mode, and load balancer target groups, you get one form focused on the container, sizing, and traffic.
Step 4: Configure the Service Basics
Give the service a name (for example, my-express-app) and select the deployment type for an HTTP web service, which is what Express Mode is tuned for. Under container image, point it at the ECR image URI you pushed in Step 2:
123456789012.dkr.ecr.us-east-1.amazonaws.com/my-express-app:latest
Set the container port to match what your app listens on (8080 in the Dockerfile example above). Add any environment variables your app needs at this stage, such as database connection strings or feature flags, rather than baking them into the image.
Step 5: Set CPU, Memory, and Networking
Choose a Fargate CPU/memory pairing sized for your workload. The table below lists standard Fargate sizing options that Express Mode services run on underneath, since Express Mode does not introduce new sizing tiers of its own.
| vCPU | Memory options | Typical use case |
|---|---|---|
| 0.25 vCPU | 0.5 GB – 2 GB | Low-traffic APIs, internal tools |
| 0.5 vCPU | 1 GB – 4 GB | Small web apps, staging environments |
| 1 vCPU | 2 GB – 8 GB | Standard production web services |
| 2 vCPU | 4 GB – 16 GB | Higher-throughput APIs, moderate background work |
| 4 vCPU | 8 GB – 30 GB | Compute-heavier services, image or PDF processing |
For networking, select the VPC and at least two subnets across separate Availability Zones. Express Mode auto-creates the security groups needed to let the Application Load Balancer reach your tasks, so you generally do not need to hand-author security group rules for a first deployment.
Step 6: Configure Auto Scaling and Health Checks
Set a minimum and maximum task count. A sensible starting point for production is a minimum of 2 (for availability across zones) and a maximum sized to your expected peak load. Express Mode wires this into standard ECS Service Auto Scaling, so the same concurrency-based scaling behavior documented for ECS applies here.
Set the health check path your app exposes (for example, /health or /). The Application Load Balancer that Express Mode provisions will poll this path, and a task that fails health checks repeatedly gets cycled out automatically.
Step 7: Deploy and Verify the Service
Review the configuration summary and create the service. Express Mode then provisions the ECS service, the ALB, the target group, the listener, the security groups, the auto scaling configuration, and a CloudWatch log group in one pass. Expect the initial rollout to take several minutes while Fargate pulls the image, starts tasks, and the ALB confirms healthy targets.
Once the service shows a healthy status, the console surfaces the ALB’s public DNS name. Test it directly:
curl -i http://my-express-app-123456789.us-east-1.elb.amazonaws.com/
# HTTP/1.1 200 OK
# content-type: application/json
# {"status":"ok","service":"my-express-app"}
If you get a 503 instead of a 200, the target group has no healthy targets yet. Give it another minute and check the ECS service events tab in the console for task startup errors before assuming something is broken.
Step 8: Inspect the Underlying ECS Resources
Because Express Mode creates standard ECS and Fargate resources rather than hiding them in a separate service, you can inspect and query everything with the normal ECS CLI. This is the biggest practical difference from App Runner, where the underlying infrastructure was never exposed to you.
aws ecs list-clusters --region us-east-1
aws ecs describe-services \
--cluster your-express-cluster \
--services my-express-app \
--region us-east-1
aws ecs list-tasks \
--cluster your-express-cluster \
--service-name my-express-app \
--region us-east-1
Use describe-services to confirm the running and desired task counts match, and check the events array in the response for anything that looks like a repeated deployment failure.
Step 9: Bring Your Own Task Definition (Advanced Configuration)
As of the July 1, 2026 update, ECS Express Mode supports custom task definitions. AWS describes the change directly: “Amazon Elastic Container Service (Amazon ECS) Express Mode now supports custom task definitions, giving you the flexibility to use existing ECS application configurations and advanced task-level customizations with Express Mode’s simplified deployment experience.”
This closes what was previously Express Mode’s biggest limitation: no way to bring sidecar containers, custom IAM task roles, or advanced volume mounts. If your app needs a sidecar (a log shipper, a service mesh proxy, or a secrets-fetching init container), register a task definition first and reference it during service creation instead of relying on Express Mode’s generated defaults.
aws ecs register-task-definition \
--family my-express-task \
--network-mode awsvpc \
--requires-compatibilities FARGATE \
--cpu "1024" \
--memory "2048" \
--container-definitions '[
{
"name": "app",
"image": "123456789012.dkr.ecr.us-east-1.amazonaws.com/my-express-app:latest",
"portMappings": [{"containerPort": 8080, "protocol": "tcp"}],
"environment": [{"name": "NODE_ENV", "value": "production"}],
"logConfiguration": {
"logDriver": "awslogs",
"options": {
"awslogs-group": "/ecs/my-express-app",
"awslogs-region": "us-east-1",
"awslogs-stream-prefix": "app"
}
}
}
]'
Reference the resulting task definition ARN when creating or updating your Express Mode service to run your custom configuration instead of the auto-generated one.
Step 10: Attach a Custom Domain
Most production services need a real domain instead of the raw ALB DNS name. Request or import a TLS certificate in AWS Certificate Manager for your domain, attach it to the ALB listener on port 443, then point your domain at the ALB using Route 53 or your existing DNS provider.
aws acm request-certificate \
--domain-name app.example.com \
--validation-method DNS \
--region us-east-1
# After DNS validation completes, create an alias record pointing to the ALB:
aws route53 change-resource-record-sets \
--hosted-zone-id Z0123456789ABC \
--change-batch '{
"Changes": [{
"Action": "UPSERT",
"ResourceRecordSet": {
"Name": "app.example.com",
"Type": "A",
"AliasTarget": {
"HostedZoneId": "Z35SXDOTRQ7X7K",
"DNSName": "my-express-app-123456789.us-east-1.elb.amazonaws.com",
"EvaluateTargetHealth": true
}
}
}]
}'
Give DNS propagation a few minutes, then confirm the certificate is serving correctly with curl -I https://app.example.com/.
Step 11: Set Up Logging and Monitoring
Express Mode auto-creates a CloudWatch log group for your service’s stdout and stderr. Tail it directly from the CLI while you are debugging a fresh deployment:
aws logs tail /ecs/my-express-app --follow --region us-east-1
For anything beyond basic log tailing, set up a CloudWatch alarm on the ALB’s HTTPCode_Target_5XX_Count and TargetResponseTime metrics so you get paged before users notice degraded performance, not after.
Step 12: Migrate an Existing App Runner Service to Express Mode
If you are reading this because you already run production traffic on App Runner, AWS’s own migration guidance and third-party migration write-ups converge on the same phased approach. Do not cut over in one step.
- Review your existing App Runner service configuration: image URI, CPU/memory size, port, environment variables, and auto scaling settings.
- Create a new ECS Express Mode service using the exact same container image and sizing, following Steps 3-8 above.
- Validate the new Express Mode service privately, using its raw ALB DNS name, before any customer traffic touches it.
- Reconfigure your custom domain (Step 10) to point at the new ALB instead of the App Runner endpoint.
- Shift traffic gradually if your DNS provider supports weighted routing, or cut over fully once you have validated the new service under real load.
- Once the Express Mode service has handled production traffic cleanly for a validation period, decommission the old App Runner service.
The cleanup command for the last step is one of the few pieces of this workflow AWS documents with an exact, verified CLI example:
aws apprunner delete-service \
--service-arn arn:aws:apprunner:us-east-1:123456789012:service/my-old-service/abc123
Do not run this until you have confirmed the Express Mode replacement is stable. There is no undo once the App Runner service and its associated resources are gone.
Understanding Express Mode Pricing
Express Mode itself carries no separate fee. It is a deployment abstraction, not a distinct billed service, so what you pay for is the standard Fargate compute, the Application Load Balancer, and CloudWatch Logs that Express Mode provisions underneath. For comparison, here is what App Runner charged versus what an equivalent Express Mode / Fargate setup costs in the main US and EU regions as of August 2026.
| Cost component | AWS App Runner | ECS Express Mode (Fargate + ALB) |
|---|---|---|
| Active vCPU | $0.064 / vCPU-hour | Standard Fargate vCPU rate (region-dependent, comparable range) |
| Active memory | $0.007 / GB-hour | Standard Fargate memory rate (region-dependent, comparable range) |
| Idle/provisioned instance | $0.007 / GB-hour, no vCPU charge | N/A — Fargate tasks are billed while running, not in a separate idle tier |
| Load balancer | Bundled into App Runner’s managed layer | Standard Application Load Balancer hourly + LCU charges apply separately |
| New feature access | Frozen as of April 30, 2026 | Actively developed (custom task definitions added July 2026) |
The practical read: Express Mode does not bundle load balancer costs the way App Runner’s managed pricing did, so a very low-traffic hobby service may see a slightly different bill shape once an always-on ALB enters the picture. For anything running sustained production traffic, the difference is marginal, and you gain visibility into every resource driving the bill.
ECS Express Mode vs. Fargate vs. Lambda: Picking the Right Fit
Express Mode is not the only way to run containers on AWS, and it is worth being clear about when it is not the right tool.
| Option | Best for | Setup complexity | Infrastructure visibility |
|---|---|---|---|
| ECS Express Mode | Simple HTTP web services and APIs, App Runner migrations | Low — single service definition | Full — standard ECS/ALB resources created for you |
| Standard ECS on Fargate | Multi-container apps, service meshes, complex networking | High — manual cluster, service, ALB, scaling setup | Full, hand-configured |
| AWS Lambda | Event-driven, short-lived functions, sporadic traffic | Low for simple functions | Limited — no persistent containers |
| Amazon EKS | Teams already standardized on Kubernetes | High — cluster and control plane management | Full, Kubernetes-native |
If your workload is a straightforward web app or API that used to fit comfortably on App Runner, Express Mode is the closest match in terms of day-to-day operational simplicity. If you need background workers, scheduled batch jobs, or multi-container pods with sidecars beyond what a single task definition supports, standard ECS or EKS remain the better fit.
Common Pitfalls When Deploying with ECS Express Mode
These are the mistakes that account for most failed first deployments, based on the ECS and Fargate patterns Express Mode is built on.
- Wrong container port. If your app listens on 3000 but you configure port 8080 in the service, health checks fail silently and tasks cycle endlessly. Match the port exactly.
- Missing subnets in two Availability Zones. Express Mode’s ALB needs subnets in at least two AZs. A VPC with only one subnet will block service creation or leave you with a single point of failure.
- Forgetting IAM permissions for ECR pull. If the ECS task execution role cannot pull from your ECR repository, tasks fail at the “pulling image” stage. Confirm the execution role has
AmazonECSTaskExecutionRolePolicyattached. - Underestimating memory for JVM or Python apps. A 0.5 GB allocation that looks fine for a Node.js hello-world app will OOM-kill a Spring Boot or Django app under real load. Size generously and tune down after observing actual usage.
- No health check endpoint. Pointing the ALB health check at a route that requires authentication or database access means a slow database makes the ALB think your whole app is down. Use a lightweight, dependency-free health route.
- Assuming source-code deployment works like early App Runner. Express Mode is image-based. If your workflow relied on App Runner pulling directly from a GitHub repo and building it for you, you now need a build step (GitHub Actions, CodeBuild, or similar) that pushes an image to ECR first.
- Not accounting for ALB costs separately. Unlike App Runner’s bundled pricing, the Application Load Balancer Express Mode creates bills on its own hourly and LCU-based schedule. Factor that into cost estimates, especially for many small low-traffic services.
- Leaving auto scaling at default minimums in production. A minimum task count of 1 means a single AZ outage can take your service down. Set a minimum of at least 2 for anything customer-facing.
Troubleshooting Guide
Work through these in order when a deployment does not behave as expected.
- Service stuck at “provisioning” for more than 10 minutes. Check
aws ecs describe-servicesfor the events array. A repeated “unable to pull image” event points to ECR permissions or a wrong image URI. - ALB returns 503 Service Unavailable. This means the target group has zero healthy targets. Check the health check path matches a real route in your app and returns a 200 status without requiring auth.
- Tasks start then immediately stop. Tail the CloudWatch logs with
aws logs tail /ecs/your-app --followto see the container’s actual crash output; this is almost always an application-level startup error, not an ECS problem. - Custom domain shows a certificate warning. Confirm the ACM certificate status is “Issued,” not “Pending validation,” and that it is attached to the HTTPS listener on the ALB, not just requested.
- High latency on first requests after scale-up. New Fargate tasks take time to start and pass health checks. If your traffic has sharp spikes, raise the minimum task count instead of relying entirely on reactive scaling.
- CLI commands fail with “AccessDenied.” Run
aws sts get-caller-identityto confirm which identity you are using, then check that identity has ECS, EC2, and IAM permissions attached. - Costs higher than expected versus old App Runner bill. Check whether you are running more minimum tasks than App Runner’s equivalent auto scaling floor, and confirm you accounted for the standalone ALB charge that App Runner used to bundle.
- Old App Runner and new Express Mode service both receiving traffic. This usually means DNS has not fully propagated, or a CDN/cache in front of your domain is still resolving to the old endpoint. Purge caches and verify with
digornslookupbefore assuming the cutover failed.
Advanced Tips for Production Deployments
Once the basic deployment is stable, a few adjustments make Express Mode hold up better under real production load.
Pin your custom task definitions to a specific image tag or digest rather than :latest. Because Express Mode now accepts custom task definitions, you get the same deployment discipline you would apply to any hand-rolled ECS service: immutable, versioned image tags make rollbacks a one-command operation instead of a rebuild.
Separate your health check route from your readiness logic. A route that checks database connectivity is useful for a dedicated readiness probe, but using it as the ALB health check means any downstream dependency hiccup takes your whole service out of rotation. Keep the ALB health check dependency-free.
Use CloudWatch Container Insights alongside the default logging Express Mode sets up. The baseline log group covers stdout/stderr, but Container Insights gives you CPU, memory, and network metrics per task without hand-instrumenting your application.
If you are migrating multiple App Runner services at once, script the ECR push and Express Mode service creation steps rather than clicking through the console repeatedly. The console flow is fine for a single service; it becomes tedious fast across a fleet.
Complete Working Example: A Minimal API on ECS Express Mode
Here is the full set of files and commands for a working end-to-end deployment, combining every step above into one reference project.
# server.js
const http = require('http');
const port = process.env.PORT || 8080;
const server = http.createServer((req, res) => {
if (req.url === '/health') {
res.writeHead(200, {'Content-Type': 'application/json'});
res.end(JSON.stringify({status: 'ok'}));
return;
}
res.writeHead(200, {'Content-Type': 'application/json'});
res.end(JSON.stringify({message: 'Hello from ECS Express Mode', env: process.env.NODE_ENV}));
});
server.listen(port, () => console.log(`Listening on ${port}`));
# Build, push, and deploy in sequence
export ACCOUNT_ID=123456789012
export REGION=us-east-1
export REPO=my-express-app
aws ecr create-repository --repository-name $REPO --region $REGION
aws ecr get-login-password --region $REGION | \
docker login --username AWS --password-stdin $ACCOUNT_ID.dkr.ecr.$REGION.amazonaws.com
docker build -t $REPO .
docker tag $REPO:latest $ACCOUNT_ID.dkr.ecr.$REGION.amazonaws.com/$REPO:latest
docker push $ACCOUNT_ID.dkr.ecr.$REGION.amazonaws.com/$REPO:latest
# Then create the Express Mode service in the ECS console using:
# Image: $ACCOUNT_ID.dkr.ecr.$REGION.amazonaws.com/$REPO:latest
# Port: 8080
# Health check path: /health
# Min tasks: 2, Max tasks: 6
That is a complete, deployable service: an image built from a two-file project, pushed to ECR, and running behind a load-balanced, auto-scaling ECS Express Mode service with health checks and logging already wired up.
Supported Regions and Known Limitations
Express Mode rolled out incrementally through 2026. AWS’s own China-region announcement confirms availability in the AWS China (Beijing) and China (Ningxia) regions at no additional charge for the capability itself, and a June 15, 2026 update added AWS GovCloud (US-East) and AWS GovCloud (US-West). AWS has not published a single consolidated regional availability table in the sources checked for this tutorial, so confirm current availability in your target region directly in the ECS console before planning a migration around it.
On limitations: Express Mode is built around HTTP web services fronted by an Application Load Balancer. It is not the tool for background workers, scheduled batch jobs, or non-HTTP protocols; for those, standard ECS task definitions or Lambda remain the better fit. It also inherits standard ECS and Fargate account quotas (clusters, services, and tasks per region), so very large migrations should check quota limits in Service Quotas before cutting over.
Securing an ECS Express Mode Service
Express Mode auto-generates a security group that lets the Application Load Balancer talk to your tasks, and that default is a reasonable starting point, but it is not the finish line. The default security group typically opens the container port only to traffic from the ALB, which is correct behavior, but you still control the ALB’s own inbound rule, and by default that listens on the internet on port 80 or 443. If the service is meant for internal use only, do not leave it publicly reachable just because the console form doesn’t prompt you to lock it down.
Scope the IAM task role narrowly. Every Express Mode service gets a task execution role for pulling images and writing logs, and optionally a task role for the application code’s own AWS API calls. Do not reuse a broad administrator role across services. If your app only reads from one S3 bucket and one DynamoDB table, write a policy that says exactly that:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": ["s3:GetObject"],
"Resource": "arn:aws:s3:::my-express-app-assets/*"
},
{
"Effect": "Allow",
"Action": ["dynamodb:GetItem", "dynamodb:PutItem"],
"Resource": "arn:aws:dynamodb:us-east-1:123456789012:table/my-express-app-data"
}
]
}
Attach that policy to a dedicated task role, not the execution role, and reference it in your custom task definition from Step 9. Keep secrets out of plain environment variables where possible; pull database credentials and API keys from AWS Secrets Manager or Systems Manager Parameter Store at container startup instead of hardcoding them into the service configuration, since environment variables set through the console are visible to anyone with read access to the ECS service definition.
Finally, enable VPC Flow Logs on the subnets hosting your Express Mode tasks if you are running anything handling customer data. It costs little and gives you a record of network traffic if you ever need to investigate an incident, which is exactly the kind of visibility App Runner’s fully-managed black box never gave you in the first place.
Automating Deployments with CI/CD
Manually building, pushing, and redeploying through the console works for the first few iterations, but any service headed to production needs a pipeline. Since Express Mode is image-based rather than source-based, the pattern is straightforward: a GitHub Actions workflow builds the image, pushes it to ECR, and forces a new deployment on the existing ECS service so it picks up the new image without you touching the console again.
# .github/workflows/deploy.yml
name: Deploy to ECS Express Mode
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::123456789012:role/github-actions-deploy
aws-region: us-east-1
- name: Login to Amazon ECR
id: ecr-login
uses: aws-actions/amazon-ecr-login@v2
- name: Build, tag, and push image
env:
REGISTRY: ${{ steps.ecr-login.outputs.registry }}
REPOSITORY: my-express-app
IMAGE_TAG: ${{ github.sha }}
run: |
docker build -t $REGISTRY/$REPOSITORY:$IMAGE_TAG .
docker push $REGISTRY/$REPOSITORY:$IMAGE_TAG
- name: Force new ECS deployment
run: |
aws ecs update-service \
--cluster your-express-cluster \
--service my-express-app \
--force-new-deployment \
--region us-east-1
Use OpenID Connect (the role-to-assume pattern above) rather than long-lived AWS access keys stored as GitHub secrets. It is a small setup cost the first time and removes an entire category of credential-leak risk from your pipeline going forward. Once this workflow is in place, every merge to main results in a fresh image pushed to ECR and a rolling deployment on the Express Mode service, with ECS handling the task replacement so the ALB never routes traffic to a half-started container.
Zero-Downtime Deployments and Rollbacks
Express Mode services deploy using the same rolling update model as standard ECS services on Fargate: new tasks start alongside old ones, the ALB only routes to a new task once it passes its health check, and old tasks are drained and stopped only after the new ones are confirmed healthy. This is what makes the force-new-deployment call in the CI/CD pipeline above safe to run on every merge; a bad image that fails health checks never receives traffic, and the previous version keeps serving requests until you intervene.
If a deployment does go bad after passing health checks (a runtime bug that only shows up under real traffic, for example), the fastest rollback is redeploying the previous image tag rather than trying to “undo” anything in Express Mode itself:
# Roll back by redeploying the last known-good task definition revision
aws ecs update-service \
--cluster your-express-cluster \
--service my-express-app \
--task-definition my-express-task:41 \
--region us-east-1
This is another place where the custom task definition support from the July 2026 update pays off: every revision of a task definition is retained by ECS, so rolling back to task definition revision 41 (or whichever number preceded the bad deploy) is a one-line command rather than a rebuild from a git tag.
Frequently Asked Questions
Is AWS App Runner shutting down completely?
No. App Runner stopped accepting new customers on April 30, 2026, but existing services continue running normally with security and maintenance support. AWS has simply stopped building new features for it and is directing new workloads to ECS Express Mode instead.
Can I still sign up for AWS App Runner in 2026?
No, unless you already had an account using App Runner before the April 30, 2026 cutoff. New AWS customers, or existing customers who never used App Runner, cannot create new App Runner services.
Does ECS Express Mode cost more than App Runner?
Not fundamentally. You pay standard Fargate vCPU and memory rates plus a standalone Application Load Balancer charge. App Runner bundled load balancing into its managed pricing, so very low-traffic services may see a slightly different bill shape, but for typical production workloads the totals are comparable.
Can I deploy directly from a GitHub repository with Express Mode, like early App Runner?
Not based on current documentation and migration guides. Express Mode is image-based: you build and push a container image to Amazon ECR (or another registry) first, then point Express Mode at that image. Add a CI step with GitHub Actions or AWS CodeBuild to automate the build-and-push part.
Does Express Mode support custom task definitions?
Yes, as of the July 1, 2026 update. You can register your own ECS task definition with sidecar containers, custom IAM roles, or advanced volume configuration and reference it in an Express Mode service instead of using the auto-generated defaults.
How long does migrating from App Runner to ECS Express Mode take?
For a single simple service, plan on an afternoon: building and validating the new Express Mode service typically takes under two hours, plus DNS propagation time before you fully retire the old App Runner service. Teams migrating many services should script the process rather than repeating it manually.
What happens to my data if I delete an App Runner service?
App Runner itself is stateless compute; deleting the service removes the running containers and its endpoint, not any external data stores like RDS or DynamoDB tables it connected to. Back up any App Runner-specific configuration (environment variables, auto scaling settings) before deleting, since those settings are not recoverable afterward.
Is Amazon EKS a better option than ECS Express Mode?
Only if your team is already standardized on Kubernetes or needs Kubernetes-specific tooling. For teams that just need a simple, load-balanced web service without managing a Kubernetes control plane, Express Mode is considerably less operational overhead.


