If you are launching or re-platforming a web application on AWS in 2026, one of the first decisions is where your code will actually run. The three realistic options for most Laravel, Node.js and Python products are AWS Lambda (serverless functions), Amazon ECS on Fargate (serverless containers) and Amazon EC2 (virtual machines, optionally running ECS or Kubernetes). All three are mature and all three can run a serious production product. They differ in how they bill you, what your team has to operate, and which kinds of workloads they handle well.
This guide is written for CTOs, founders and engineering leads who want a practical answer rather than a marketing comparison. We cover how each option bills, where each one wins, the gotchas that catch teams out, and a simple framework for choosing.
The short answer
- Choose Lambda for spiky, low-to-medium or unpredictable traffic, event-driven work (queues, webhooks, file processing, scheduled jobs) and products where scaling to zero matters.
- Choose ECS on Fargate for a containerised web app or API that runs all day with fairly predictable traffic, when you do not want to manage servers.
- Choose EC2 (directly or as ECS/EKS capacity) for steady, high-utilisation workloads, special hardware such as GPUs, software that needs OS-level control, or when you can commit to a Savings Plan and keep instances busy.
Many good architectures mix them: a Fargate service for the main web app, Lambda for background and event processing, and EC2 only where it is clearly cheaper or required.
How each option bills you
The billing unit explains most of the cost differences, so it is worth understanding before looking at any numbers.
| AWS Lambda | ECS on Fargate | Amazon EC2 | |
|---|---|---|---|
| You pay for | Requests plus execution time × configured memory (per ms) | vCPU and memory allocated to each running task (per second, one-minute minimum) | Each running instance (per second for Linux) |
| Scales to zero | Yes | No (a service keeps at least one task running unless you stop it) | No |
| Cost while idle | None | Full task price | Full instance price |
| Free tier | 1 million requests and 400,000 GB-seconds per month | None | Limited, for new accounts |
| OS and runtime patching | AWS | AWS (you maintain your container image) | You |
| Cold starts | Yes | Only when new tasks start | No, once running |
| Max request/job duration | 15 minutes | No practical limit | No limit |
All three are covered by AWS Compute Savings Plans, which give a discount in exchange for committing to a steady hourly spend for one or three years. The discount is typically smaller for Lambda than for Fargate, and largest for EC2, so commitments tend to favour instance-based options for steady workloads.
A worked cost example
Prices change and vary by region, so always confirm on the AWS pricing pages before deciding. At the time of writing, US East (N. Virginia) on-demand list prices for x86 are roughly:
- Lambda: $0.20 per million requests and about $0.0000166667 per GB-second.
- Fargate (Linux, x86): about $0.04048 per vCPU-hour and $0.004445 per GB-hour.
Here is how to model a typical API with these units. The script below is a quick estimator you can adapt with your own traffic figures:
# Rough monthly compute estimate (compute only, excludes load balancer,
# API Gateway, data transfer, logs and databases)
HOURS = 730
def lambda_cost(requests_per_month, avg_ms, memory_gb):
gb_seconds = requests_per_month * (avg_ms / 1000) * memory_gb
billable_gbs = max(gb_seconds - 400_000, 0) # free tier
billable_req = max(requests_per_month - 1_000_000, 0)
return billable_gbs * 0.0000166667 + billable_req / 1_000_000 * 0.20
def fargate_cost(tasks, vcpu, memory_gb):
return tasks * HOURS * (vcpu * 0.04048 + memory_gb * 0.004445)
print("Lambda, 5M req, 120 ms, 1 GB :", round(lambda_cost(5_000_000, 120, 1), 2))
print("Lambda, 60M req, 120 ms, 1 GB:", round(lambda_cost(60_000_000, 120, 1), 2))
print("Fargate, 2 tasks, 1 vCPU, 2 GB:", round(fargate_cost(2, 1, 2), 2))
Running it gives roughly $4 a month for 5 million Lambda requests, about $125 for 60 million, and about $72 for two always-on 1 vCPU / 2 GB Fargate tasks. The pattern is what matters: Lambda is extremely cheap at low and bursty volumes, but its cost grows in a straight line with traffic, while Fargate and EC2 cost the same whether a task is busy or idle. Once your containers would be busy for a large share of the day, Fargate or EC2 usually becomes the cheaper option.
Two things often matter more than the compute line itself:
- The front door. Lambda behind API Gateway adds a per-request charge that can exceed the Lambda cost at high volume. A Lambda Function URL or an Application Load Balancer can be cheaper. Fargate and EC2 web apps normally sit behind an Application Load Balancer, which has a fixed hourly charge plus usage.
- Networking and logs. NAT Gateway data processing and CloudWatch Logs ingestion regularly surprise teams. Use VPC endpoints for S3 and other AWS services, and set log retention from day one.
If your AWS bill is already higher than expected, our cloud cost optimisation service starts with exactly this kind of breakdown.
When AWS Lambda is the right choice
1. Spiky or unpredictable traffic
Marketing sites with campaign spikes, B2B tools used mainly during office hours, MVPs whose traffic you cannot predict yet: Lambda scales up automatically and costs almost nothing when nobody is using it.
2. Event-driven and background work
Lambda is a natural fit for processing SQS messages, S3 uploads (image resizing, PDF generation, document parsing for AI pipelines), webhooks from Stripe or Shopify, and scheduled jobs through EventBridge Scheduler. Even teams that run their main app on containers often use Lambda here.
3. Laravel and Node.js on Lambda
Node.js and Python run natively on Lambda. PHP runs through a custom runtime layer, most commonly the open source Bref project, or through a managed platform such as Laravel Vapor. A minimal Bref setup with the Serverless Framework looks like this:
# serverless.yml (Laravel on Lambda with Bref)
service: my-laravel-app
provider:
name: aws
region: eu-west-2
environment:
APP_ENV: production
QUEUE_CONNECTION: sqs
plugins:
- ./vendor/bref/bref
functions:
web:
handler: public/index.php
runtime: php-83-fpm
timeout: 28
events:
- httpApi: '*'
artisan:
handler: artisan
runtime: php-83-console
timeout: 720
events:
- schedule:
rate: rate(1 minute)
input: '"schedule:run"'
Lambda gotchas to plan for
- Cold starts. The first request to a new execution environment is slower. It is usually acceptable for APIs, but noticeable for latency-sensitive endpoints. Provisioned concurrency removes it at a cost.
- Time limits. Functions stop at 15 minutes, and API Gateway has its own integration timeout (29 seconds by default). Long reports, exports and AI jobs should move to a queue.
- Database connections. Thousands of concurrent functions can exhaust PostgreSQL or MySQL connections. Use RDS Proxy or keep concurrency limits sensible.
- No local disk or sticky state. Sessions, cache and uploads must live in Redis, DynamoDB or S3, never on the function's filesystem.
When ECS on Fargate is the right choice
Fargate is the default we recommend most often for a containerised web application or API that runs continuously. You get the portability of Docker and a normal long-running process, without patching servers or managing a cluster's capacity.
Why teams like it
- Your app runs as a normal server. Laravel with PHP-FPM and Nginx, Laravel Octane, a Next.js server, an Express or NestJS API, or a FastAPI service runs exactly as it does locally in Docker.
- Long requests, WebSockets and workers. There is no 15-minute ceiling, so queue workers, Laravel Horizon, Reverb WebSocket servers and long-running AI agents work without workarounds.
- Clean scaling. Service auto scaling can add tasks based on CPU, memory or request count per target.
- Cost levers. Graviton (Arm) tasks are cheaper than x86, and Fargate Spot gives large discounts for interruption-tolerant workers.
A typical Laravel or Node.js setup on Fargate has one service for web traffic behind an Application Load Balancer, a second service for queue workers, and a scheduled task for cron. Here is a trimmed task definition for the web container:
{
"family": "app-web",
"requiresCompatibilities": ["FARGATE"],
"networkMode": "awsvpc",
"cpu": "512",
"memory": "1024",
"runtimePlatform": { "cpuArchitecture": "ARM64", "operatingSystemFamily": "LINUX" },
"containerDefinitions": [{
"name": "web",
"image": "123456789012.dkr.ecr.eu-west-2.amazonaws.com/app:latest",
"portMappings": [{ "containerPort": 8080 }],
"secrets": [{ "name": "DB_PASSWORD", "valueFrom": "arn:aws:secretsmanager:eu-west-2:123456789012:secret:app/db" }],
"healthCheck": { "command": ["CMD-SHELL", "curl -f http://localhost:8080/up || exit 1"] },
"logConfiguration": { "logDriver": "awslogs", "options": {
"awslogs-group": "/ecs/app-web", "awslogs-region": "eu-west-2", "awslogs-stream-prefix": "web" } }
}]
}
Fargate gotchas
- You pay for idle tasks. A staging environment left running all month costs the same as one used constantly. Schedule non-production services to scale to zero out of hours.
- Networking costs. Tasks in private subnets pulling images and calling AWS APIs through a NAT Gateway can add significant data processing charges. VPC endpoints help.
- Image size and start time. Large images slow down deployments and scaling. Use multi-stage Docker builds and slim base images.
When EC2 is the right choice
EC2 gives you the most control and, for steady workloads, usually the lowest unit price, but you take on more operational work.
- Steady, high utilisation. If your servers are busy most of the day and you can commit to a Savings Plan or Reserved Instances, EC2 is typically the cheapest per unit of compute.
- Special hardware. GPU instances for self-hosted AI models, high-memory instances for analytics, or local NVMe storage.
- OS-level control. Legacy applications, licensed software, custom kernels or agents that cannot run in a container.
- Container packing. Running ECS or EKS on EC2 capacity lets you pack many containers onto fewer instances. Managed options such as ECS Managed Instances reduce the patching burden while keeping EC2 pricing.
The trade-off is real: someone has to patch the OS, manage AMIs, configure auto scaling groups, handle instance failures and right-size regularly. A half-empty fleet of reserved instances can easily cost more than Fargate. For a small team without dedicated DevOps capacity, that operational cost often outweighs the price advantage.
Practical differences that catch teams out
| Concern | Lambda | Fargate | EC2 |
|---|---|---|---|
| WebSockets / long-lived connections | Via API Gateway WebSocket APIs only | Native | Native |
| Long-running jobs (>15 min) | Not supported; use Step Functions or containers | Supported | Supported |
| Local development parity | Needs emulation or tooling | Same Docker image as local | Same as local if containerised |
| Deployment | Upload function code or image | Push image, update service (rolling or blue/green) | AMIs, CodeDeploy, or containers on top |
| Vendor lock-in | Highest | Low (standard containers) | Lowest |
| Ops effort | Lowest | Low | Highest |
A simple decision framework
- Is the workload event-driven or idle much of the time? Start with Lambda.
- Is it a web app or API that runs all day, uses WebSockets, long requests or persistent workers? Use ECS on Fargate.
- Are your containers busy most of the day, is spend high enough that a few percent matters, and do you have DevOps capacity? Move steady services to EC2 capacity with a Savings Plan.
- Do you need GPUs, OS control or licensed software? EC2.
- Not sure yet? Containerise the app and start on Fargate. A Docker image moves easily to EC2-backed ECS later, and you can peel off background work into Lambda as it becomes clear.
Whatever you choose, define it in infrastructure as code (Terraform, AWS CDK or CloudFormation), set budgets and cost alerts in AWS Budgets on day one, and tag resources by environment so you can see what each part of the product actually costs.
Summary
Lambda is the cheapest and simplest option for spiky, event-driven and low-volume workloads, but its cost grows with every request and it has hard limits on duration and connections. ECS on Fargate is the best default for most always-on Laravel, Node.js and Python web applications: real containers, no servers to manage and predictable cost. EC2 wins for steady, high-utilisation workloads with committed spend, special hardware or OS-level needs, at the price of more operational work. The best architectures often combine them, and the right answer depends on your traffic shape, team size and growth plans rather than on any single price table.
FAQ
Is AWS Lambda cheaper than Fargate?
At low or bursty traffic, yes, often by a wide margin because Lambda costs nothing when idle and includes a monthly free tier. For an API that is busy most of the day, Fargate is usually cheaper because its cost does not grow with each request.
Can I run Laravel on AWS Lambda?
Yes. Laravel runs on Lambda through the open source Bref runtime or managed platforms such as Laravel Vapor. Sessions, cache, queues and file storage need to move to services like Redis, SQS and S3.
Is Fargate more expensive than EC2?
On list price the gap is smaller than many assume, especially with Graviton tasks. EC2 becomes clearly cheaper when instances are highly utilised and covered by a Savings Plan; half-empty EC2 fleets are often more expensive overall.
What about cold starts on Lambda?
Cold starts add latency to the first request handled by a new execution environment. For most business APIs this is acceptable; for latency-critical endpoints use provisioned concurrency or run that part on containers.
Should I use EKS (Kubernetes) instead of ECS?
Choose EKS if your team already runs Kubernetes or needs its ecosystem. For most small and mid-sized product teams on AWS, ECS is simpler to operate and does everything they need.
Can I switch between Lambda, Fargate and EC2 later?
Moving between Fargate and EC2-backed ECS is straightforward because both run the same container image. Moving to or from Lambda takes more work because request handling, timeouts and state must be adapted.
Written by
Prakash Tank
Founder & Full-Stack Architect, DayDecoder
Prakash started as a certified Laravel developer and grew into a full-stack architect who owns a project end to end: requirements, architecture, development, deployment, and support. He designs event-driven systems with...
More about Prakash