Back to resources
// architecture · compute

EC2, ECS or Lambda: how I choose

The question comes up on every project, and the wrong answer is expensive — in money or in sleepless nights. Here's the decision tree I use, based on load, budget and team size, not on hype.

TechnicalJul 15, 2026~8 min · intermediate
EC2ECS/FargateLambdaDockerauto-scaling
01

The three models

They're three levels of abstraction. The higher you go, the less server you manage — but the less you control, and the cost model changes entirely.

EC2a machine of your own. Full control, you manage the OS. Cost: hourly, running or idle.
ECS/Fargateyour container, no machine to manage. Cost: vCPU + RAM × duration.
Lambdajust your function. Zero server, scales to zero. Cost: per millisecond.
02

The decision tree

I ask myself three questions, in this order.

01
Is the traffic intermittent?

Event-driven, rare spikes, or near-zero most of the time → Lambda. You pay nothing while it sleeps.

02
Constant, containerized load?

An API running 24/7, already in Docker, several services → ECS/Fargate. The sweet spot.

03
Need fine control?

Legacy PHP, GPU, precise system config, or you want the lowest cost at stable load → EC2.

04
Small team?

The smaller you are, the higher you go: let AWS manage the machines for you.

03

What it looks like

Lambda — a function

handler.tscopy
// Lambda : le code, zero serveur a gerer
export async function handler(event) {
return { statusCode: 200, body: "hello" };
}
// tu paies a la milliseconde d'execution. A l'arret : 0.

ECS/Fargate — a container

Dockerfilecopy
# ECS/Fargate : ton conteneur, sans gerer de machine
FROM node:20-slim
WORKDIR /app
COPY package*.json ./
RUN npm ci --omit=dev
COPY . .
CMD ["node", "server.js"]
# Fargate lance ce conteneur ; tu paies vCPU + RAM x duree
i

For EC2, deployment is the one from my Langfuse and e-commerce guides: machine, reverse proxy, HTTPS, pm2 or Docker.

04

The cost traps

Lambda gets expensive when…
traffic becomes constant and high
functions run long (>1s)
cold starts hurt latency
EC2 gets expensive when…
the machine idles overnight
nobody does the rightsizing
traffic is very irregular
!

There's no absolute winner: the right choice depends on your traffic curve. In doubt on a stable load, ECS/Fargate is rarely a bad bet.

05

Lambda up close: cold starts, concurrency, 15 min

The tree above says “intermittent traffic → Lambda”, but before putting everything there you need to know three walls I hit regularly in production. They’re what decide whether Lambda holds up or not.

01
The 15-minute wall

A single invocation can’t exceed 900 seconds — a hard, non-negotiable ceiling, with at most 10,240 MB of RAM ([Lambda quotas](https://docs.aws.amazon.com/lambda/latest/dg/gettingstarted-limits.html)). A batch that runs over → you split it, move to Step Functions, or push the task onto Fargate.

02
The concurrency wall

By default, 1,000 concurrent executions for your whole account in a region, shared across all your functions ([function scaling](https://docs.aws.amazon.com/lambda/latest/dg/lambda-concurrency.html)). Past that, throttling: requests get dropped. It’s raisable, but you have to ask — and remember reserved concurrency to protect your critical functions.

03
The cold-start wall

When no warm environment is available, Lambda spins up a fresh one: that’s the cold start, from a few hundred ms to several seconds depending on runtime and your dependencies. Painful on a user-facing API, invisible on batch.

Two ways to kill the cold start

SnapStart — free

Java, Python 3.12+, .NET 8+

Firecracker snapshot of the initialized env, restored warm
down to sub-second startup, at no extra cost
watch state uniqueness (seeds, connections) — [SnapStart docs](https://docs.aws.amazon.com/lambda/latest/dg/snapstart.html)
Provisioned concurrency — paid

all runtimes

N pre-initialized environments, millisecond response
zero cold start as long as you stay under the threshold
you pay to keep them warm, even idle
i

My rule: SnapStart first when the runtime supports it (it’s free), provisioned concurrency only if I have a strict latency SLA that SnapStart can’t meet. And if functions run long or continuously, I re-read the tree — often that’s the sign it’s time to move to ECS.

06

Fargate or EC2: where the curve crosses

Once you’ve chosen containers, the sub-choice remains: Fargate (AWS manages the machines) or the EC2 launch type (you manage your fleet under ECS). It’s not religion, it’s a matter of utilization rate.

Fargateyou pay exactly the vCPU + RAM of each task, zero machine to patch. Wins at low utilization or spiky load.
EC2 launch typeyou bin-pack several tasks onto your instances and apply Savings Plans / Spot. Wins when your instances run well-filled.

The AWS Fargate vs EC2 blog puts numbers on the crossover: at low reservation rates, Fargate can be up to ~87% cheaper than an under-used instance; at full load, the EC2 launch type pulls ahead with over 20% savings. The tipping point is your ability to keep instances filled.

The path most apps follow

Start: one Lambda or one Fargate task. Zero ops, you pay what you use, you ship.
Growth: traffic stabilizes, the Fargate bill climbs — you add Savings Plans, still without managing a server.
Scale: several services run 24/7 and well-filled. Only then does the EC2 launch type (or bare EC2 for GPU / fine config) become worth it, at the cost of ops.

Many teams end up mixed: Fargate for spiky or low-use services, EC2 for the stable core that justifies a Savings Plan. You’re never forced to pick one launch type for the whole cluster.

99

Sources & further reading

Don't pick by hype. Intermittent traffic → Lambda; stable containerized load → ECS; fine control or floor cost → EC2. And whatever you pick, watch the bill: the wrong model shows up there first.