Updated Nov 5, 20267 min read

ECS vs EC2: How to Run Containers and Backends on AWS

EC2 gives you virtual machines and ECS schedules containers onto them or onto Fargate. What each one leaves to you, how they combine, and how to get a containerized backend running on AWS from application code.

Amazon EC2 is the AWS service for virtual machines, and for years the default way to run a backend on AWS was an instance with your app, a process manager and a deploy script. It stays simple until there are several services, uneven traffic and an operating system to patch on every box, at which point a common next step is packaging the app as a container and looking at ECS.

ECS is not a replacement for EC2 so much as a layer on top of it: it schedules containers onto EC2 instances you run, or onto Fargate, where AWS runs the servers. This guide compares the three ways of running a backend that come out of that choice and shows where Encore (infrastructure from code) fits.

ECS vs EC2 at a glance

Encore (ECS on Fargate)EC2 directlyECS on EC2ECS on Fargate
Unit you deployYour application codeAn AMI or a deploy scriptA task definition (containers)A task definition (containers)
Servers to manageNoneInstances, OS, patchingInstances in an Auto Scaling groupNone
ScalingConfigured per environmentAuto Scaling groupsService auto scaling plus capacity providersService auto scaling
NetworkingVPC, subnets and load balancer provisionedYou build the VPC and load balancerawsvpc per task, ENI limits per instanceawsvpc per task
Local developmentencore run with local infrastructureWhatever you set upDocker Compose or similarDocker Compose or similar
Cost modelFargate tasks and resources in your accountPer instance-hourPer instance-hour, no ECS chargePer task vCPU and memory

ECS on Fargate from application code with Encore

Encore

Encore is infrastructure from code for TypeScript and Go, with a platform that provisions and deploys into your own AWS or GCP account, once you connect your cloud account. On AWS you choose Fargate or EKS as the compute for an environment, and Encore builds a container from your code and creates the ECR repository, the Fargate services and task definitions, an Application Load Balancer and a VPC with public, compute and storage subnets, as described in the AWS infrastructure docs.

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.

Set up the app

Get started
brew install encoredev/tap/encore &&
encore app create
Copy

Run in your terminal to get started locally.

~
$ encore app create orders --example=ts/empty$ cd orders && mkdir orders

A service with an endpoint and a Postgres database is ordinary TypeScript, and there is no task definition, Dockerfile or target group to keep next to it:

// orders/encore.service.ts import { Service } from "encore.dev/service"; export default new Service("orders");
// orders/orders.ts import { api } from "encore.dev/api"; import { SQLDatabase } from "encore.dev/storage/sqldb"; // RDS for PostgreSQL on AWS, a local Postgres under encore run. const db = new SQLDatabase("orders", { migrations: "./migrations" }); export const create = api( { expose: true, method: "POST", path: "/orders" }, async ({ sku }: { sku: string }): Promise<{ id: number }> => { const row = await db.queryRow<{ id: number }>` INSERT INTO orders (sku) VALUES (${sku}) RETURNING id`; return { id: row!.id }; }, );
-- orders/migrations/1_create_orders.up.sql CREATE TABLE orders ( id BIGSERIAL PRIMARY KEY, sku TEXT NOT NULL, created_at TIMESTAMPTZ NOT NULL DEFAULT now() );

encore run starts Postgres locally and runs the service, and the local development dashboard shows each request with its database query in a trace. When you push, the same code becomes a Fargate service behind the load balancer with an RDS database in the private storage subnet, and Encore provisions an IAM role for the service. Deploys roll out new tasks gradually behind load balancer health checks. Database sizing and other common settings are edited per environment in the dashboard, and changes you make in the AWS console are not overwritten on the next deploy.

A second service is another folder with its own encore.service.ts. A per-environment process allocation setting decides whether services share one Fargate service or each get their own, a choice that hand-written ECS setups make by copying task definitions. An AI coding agent working in the repo adds that service, runs it with encore run, and the deploy creates the ECS resources for it in the same change.

Best fit: TypeScript and Go teams who want their backend on ECS and Fargate in their own AWS account, defined by the code they run locally.

EC2 directly

Amazon EC2 gives you virtual machines with a choice of instance families, and you install and run whatever you want on them. A typical setup is a launch template with a user-data script or a baked AMI, an Auto Scaling group across two Availability Zones, and an Application Load Balancer in front.

Everything above the hypervisor is yours: OS patches, the Node.js or Go runtime, log shipping, the process manager and the deploy mechanism, whether that is CodeDeploy, an SSH script or replacing instances with a new AMI. That control is the reason to pick EC2 for workloads that need a specific kernel setting, local NVMe storage or long-lived processes that do not fit a container scheduler, and it is also why a second and third service usually means a second and third set of scripts.

Good to know

Running one service per instance leaves a lot of idle capacity on small services, and running several on one instance makes deploys and resource limits your problem, which is the gap container orchestration fills.

ECS on EC2

ECS runs containers as tasks, described by a task definition that lists images, CPU and memory, ports, environment variables and an IAM task role. A service keeps a desired number of tasks running and registers them with a load balancer target group. With the EC2 launch type, those tasks land on container instances in your cluster, EC2 instances running the ECS agent, usually from the ECS-optimized AMI, and grouped in an Auto Scaling group that ECS scales through a capacity provider.

ECS has no charge of its own on the EC2 launch type, as the ECS pricing page notes, so the cost is the instances, and packing many small tasks onto a few larger instances can be cheaper than Fargate at steady, high utilization. The trade is that you still patch and replace the instances, keep enough spare capacity for deploys, and plan around networking limits: in awsvpc mode each task gets its own network interface, and the number of interfaces per instance is limited unless you enable ENI trunking.

Good to know

The EC2 launch type is the way to get GPUs, specific instance families and daemon tasks that run on every host, which are the most common reasons teams keep it alongside Fargate.

ECS on Fargate

With the Fargate launch type the task definition is the same, and AWS supplies the compute for each task, so there is no cluster capacity, AMI or agent to maintain. You pick CPU and memory per task from the supported combinations and pay for those while the task runs. Each task gets its own network interface in your subnets, and scaling is service auto scaling on CPU, memory or request count.

Fargate removes the instance layer, and the rest of the setup stays with you: the VPC and subnets, the load balancer and target groups, the ECR repository, task and execution roles, security groups, secrets from Secrets Manager or Parameter Store, and a pipeline that builds an image and registers a new task definition revision on every deploy. Teams usually write that in Terraform or CDK, and it grows with every service.

Which one to use

EC2 directly suits single, long-lived workloads that need host-level control. ECS on EC2 suits container workloads that need GPUs or specific instances, or that run at high, steady utilization where packing pays off. ECS on Fargate suits most containerized backends, with the servers managed by AWS.

Pick Encore when you want ECS on Fargate in your own AWS account with the VPC, load balancer, databases derived from your TypeScript or Go code, and the same code running locally under encore run.

Frequently asked questions

What is the difference between ECS and EC2?

EC2 is the AWS service for virtual machines, where you manage the operating system and whatever runs on it. ECS is a container orchestrator that runs your containers as tasks and services, either on EC2 instances you manage or on Fargate, where AWS manages the servers.

Is ECS cheaper than EC2?

ECS itself has no extra charge, so ECS on EC2 costs the same as the instances it runs on, and dense packing can make it cheaper than one app per instance. ECS on Fargate charges per task for vCPU and memory, which costs more per unit of compute but removes idle instance capacity and server maintenance.

Should I use ECS with EC2 or Fargate?

Use Fargate when you want containers without managing instances, patching or cluster capacity. Use the EC2 launch type when you need GPUs, specific instance types, very high steady utilization, or host-level access that Fargate does not offer.

How do I deploy a TypeScript backend to ECS without writing task definitions?

With Encore, define services and APIs in TypeScript with api() from encore.dev/api, connect your AWS account and choose Fargate as the compute for an environment. On git push, Encore builds the container and creates the Fargate services, load balancer and VPC in your account, and Encore provisions an IAM role for the service.

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