Updated Nov 5, 20267 min read

How to Deploy a Docker Compose App to AWS in 2026

A docker-compose.yml describes an app, a database, a cache and a worker on one machine. AWS splits those into separate managed services, and this guide covers four ways to make that move.

Docker Compose is how most backends run on a laptop: an app container, a Postgres container, a Redis container and a worker, wired together in one docker-compose.yml. AWS has no service that runs that file as-is, so deploying means deciding where each of those containers goes.

Docker's Compose integration for Amazon ECS was retired in November 2023, and AWS Copilot, the CLI widely used instead, reached end of support on June 12, 2026. This guide covers the four routes left in 2026, starting with the one that has no translation step.

How Compose services map to AWS

A typical Compose file has four kinds of services, and each one has a managed equivalent on AWS:

Compose serviceWith EncoreOn EC2On ECS (Express Mode or CDK/Terraform)
App containerFargate service, from your codeSame container on the instanceECS service on Fargate behind a load balancer
postgresRDS, declared in codeContainer on the instance, or RDSRDS or Aurora, created separately
redisElastiCache, declared in codeContainer on the instance, or ElastiCacheElastiCache, created separately
worker + queueSNS and SQS with a subscriptionContainer on the instanceSecond ECS service plus SQS
VolumesS3 bucket for files, RDS for dataEBS disk on the instanceEFS, or S3 for files
.env fileSecrets in Secrets ManagerFile on the instanceSecrets Manager or Parameter Store
Best fitRunning each Compose service on AWS with its database and queues created from codeOne small app on one machineTeams that want to own every ECS and VPC setting

Each option is covered below, starting with Encore.

Declaring the Compose services in code with Encore

Encore

Encore is a tool that works alongside your framework for TypeScript and Go, with a platform that provisions and deploys into your own AWS or GCP account. Instead of translating docker-compose.yml into task definitions, the services declare the database, cache and queue they use in code, and Encore provisions RDS, ElastiCache, SNS and SQS, and Fargate in your AWS account, and Encore provisions an IAM role for the service, as an alternative to writing Terraform.

Application code passes through Encore and infrastructure guardrails to resources provisioned in your own AWS or GCP account.
Encore provisions the infrastructure your application needs in your own AWS or GCP account.

Here is a catalog service that replaces three Compose services at once, with the Postgres container becoming a database, the Redis container a cache cluster and the worker a Pub/Sub subscription:

// catalog/catalog.ts import { api, APIError } from "encore.dev/api"; import { CacheCluster, StringKeyspace, expireIn } from "encore.dev/storage/cache"; import { Subscription, Topic } from "encore.dev/pubsub"; import { SQLDatabase } from "encore.dev/storage/sqldb"; // docker-compose "postgres" service -> RDS on AWS const db = new SQLDatabase("catalog", { migrations: "./migrations" }); // docker-compose "redis" service -> ElastiCache on AWS const cache = new CacheCluster("catalog-cache", { evictionPolicy: "allkeys-lru" }); const productCache = new StringKeyspace<{ id: number }>(cache, { keyPattern: "product/:id", defaultExpiry: expireIn(60 * 1000), }); // docker-compose "worker" service consuming a queue -> SNS and SQS on AWS interface PriceChanged { id: number; priceCents: number; } export const priceChanged = new Topic<PriceChanged>("price-changed", { deliveryGuarantee: "at-least-once", }); interface Product { id: number; name: string; priceCents: number; } export const get = api( { expose: true, method: "GET", path: "/products/:id" }, async ({ id }: { id: number }): Promise<Product> => { const cached = await productCache.get({ id }); if (cached) return JSON.parse(cached) as Product; const row = await db.queryRow<Product>` SELECT id, name, price_cents AS "priceCents" FROM products WHERE id = ${id}`; if (!row) throw APIError.notFound("product not found"); await productCache.set({ id }, JSON.stringify(row)); return row; }, ); export const setPrice = api( { expose: true, method: "POST", path: "/products/:id/price" }, async ({ id, priceCents }: { id: number; priceCents: number }): Promise<void> => { await db.exec`UPDATE products SET price_cents = ${priceCents} WHERE id = ${id}`; await productCache.delete({ id }); await priceChanged.publish({ id, priceCents }); }, ); new Subscription(priceChanged, "notify-watchers", { handler: async (event) => { // The work the compose "worker" container used to do. console.log("price changed", event.id, event.priceCents); }, });

The migration in catalog/migrations creates the products table the queries use:

-- catalog/migrations/1_create_products.up.sql CREATE TABLE products ( id BIGSERIAL PRIMARY KEY, name TEXT NOT NULL, price_cents INTEGER NOT NULL );
Get started
brew install encoredev/tap/encore &&
encore app create
Copy

Run in your terminal to get started locally.

encore run starts Postgres locally along with a local cache and Pub/Sub, so the whole stack runs without a docker-compose.yml. Once you connect your AWS account, a git push provisions the RDS database, the ElastiCache cluster, the SNS topic and SQS queue, and the Fargate services, and if you still need a container image for another platform, encore build docker produces one.

The Infrastructure page in the Encore dashboard with a database's configuration panel open, showing fields for vCPUs, memory, storage, availability type, max connections and backups.
Each provisioned resource can be reviewed and its configuration edited per environment in the Encore dashboard. The screenshot shows a GCP Cloud SQL database.

Coding agents that work in the repository see the database, cache and queue as typed declarations next to the code that uses them, so adding a resource is a code change rather than an edit to a Compose file and a separate set of Terraform modules.

Best fit: teams that want their Compose app on managed AWS services in their own account.

Option 2: Docker Compose on an EC2 instance

Docker Compose on EC2

The shortest path is to launch an EC2 instance, install Docker Engine and the Compose plugin, copy the repository over and run docker compose up -d. The Compose file works unchanged, which makes this the quickest way to get a demo onto a public IP.

Everything the Compose file used to hide becomes your job in production: the instance is a single point of failure, Postgres data sits on an EBS volume you snapshot yourself, deploys mean SSH or a script that pulls new images, and the operating system needs patching. A common middle step is keeping the app containers on EC2 and moving Postgres to RDS, which removes the riskiest part of the setup.

Best fit: a single small app, a staging copy or an internal tool where downtime during a deploy is acceptable.

Option 3: ECS Express Mode for each container

ECS Express Mode

ECS Express Mode takes a container image, a task execution role and an infrastructure role, and creates a Fargate service with a URL, a load balancer with TLS, autoscaling, monitoring and networking. Each web-facing container from the Compose file becomes one Express Mode service, and AWS shares load balancers across services with the same networking configuration.

Express Mode covers the containers only, so the Postgres and Redis services from the Compose file still need to be created as RDS and ElastiCache, placed in the same VPC, and wired in through environment variables and secrets, and a worker that consumes a queue needs its own service and an SQS queue.

Best fit: teams with one or two web containers that want them running on Fargate.

Option 4: ECS task definitions with CDK or Terraform

AWS CDK

The most flexible route is translating each Compose service into an ECS task definition and service, defined in AWS CDK or Terraform alongside the VPC, load balancer, RDS instance, ElastiCache cluster, security groups and IAM roles. AWS now points former Copilot users to CDK L3 constructs for this kind of setup.

The Compose file is a starting point rather than an input: ports, environment variables, health checks and volumes all have to be rewritten in ECS terms, and the infrastructure code also has to describe resources the Compose file never mentioned, such as the VPC, security groups and IAM roles, and the team controls every networking and scaling setting.

Best fit: platform teams that want full control over the ECS setup and already maintain infrastructure code.

Which route to choose

Run Compose on EC2 when the app is small and a single machine is acceptable. Use ECS Express Mode when you have a few web containers and are willing to create the database and cache yourself, and write task definitions in CDK or Terraform when you need control over every setting. Choose Encore when you want the Compose services to become managed AWS resources without maintaining the translation, and see replacing Docker Compose and Terraform for a line-by-line comparison of the two setups.

Frequently asked questions

Can I deploy docker-compose.yml directly to AWS?

Not with Docker's own tooling any more: the Compose integration for Amazon ECS was retired in November 2023, and AWS Copilot reached end of support on June 12, 2026. The direct route left is running Docker Compose on an EC2 instance, while the managed routes translate each Compose service into an ECS service, an RDS database or an ElastiCache cluster.

Is running Docker Compose on EC2 good enough for production?

It works for small apps that fit on one instance, but the instance is a single point of failure, the database lives on a disk you back up yourself, and you patch the operating system. Moving the database to RDS first removes the riskiest part, even when the app containers stay on EC2.

What replaces the postgres and redis services from docker-compose.yml on AWS?

Amazon RDS replaces the Postgres container and Amazon ElastiCache replaces the Redis container, both running outside your application containers with managed backups and failover. The app containers then run on ECS with Fargate and connect to them over the VPC.

How do I move a Docker Compose app with Postgres, Redis and a worker to AWS with Encore?

Declare the database with new SQLDatabase, the cache with new CacheCluster and a StringKeyspace, and replace the worker's queue with a Topic and a Subscription. encore run starts Postgres locally, and deploying to an environment connected to your AWS account provisions RDS, ElastiCache, SNS and SQS, and Fargate.

Deploy to your cloud on AWS and Google Cloud
without managing infrastructure

Encore lets developers and agents define application infrastructure directly in code, then automatically provisions it from local development to production in your AWS or GCP account.

~/orders — claude
Claude Code
Claude Code v2.1.180Opus 5.5~/orders