Introduction
"Serverless" is one of the most overloaded terms in cloud computing. When AWS Lambda launched in 2014, serverless meant event-driven functions that run in response to triggers, scale to zero, and bill per invocation. A decade later, the category has expanded to include edge isolates, container-based functions, orchestration frameworks, and globally distributed compute.
The critical distinction that most comparisons miss: there are two fundamentally different serverless architectures, and they make different trade-offs.
Container-based serverless (AWS Lambda, Google Cloud Functions, Azure Functions) runs your code in containers or microVMs within specific cloud regions. Containers provide full language runtimes, large memory allocations, and access to the operating system — but they take time to start (cold starts), they run in one region at a time, and they bill for wall-clock time including I/O wait.
Isolate-based serverless (Cloudflare Workers) runs your code in V8 isolates at edge locations worldwide. Isolates start in under a millisecond, deploy globally in seconds, and bill for CPU time only — but they are limited to JavaScript/TypeScript/WASM, have smaller memory allocations, and cannot access the file system or native OS APIs.
This architectural difference determines cold start behavior, language support, execution limits, pricing, global distribution, and what you can build. Neither is universally better. Understanding when each model wins is the point of this comparison.
Runtime Architecture
Cloudflare Workers: V8 Isolates at Every Edge
Workers uses V8 isolates — the same JavaScript engine that powers Google Chrome. Instead of spinning up a container for each function invocation, Workers creates a lightweight execution context within an already-running V8 process.
How isolates work:
A V8 isolate is an independent instance of the V8 engine with its own heap memory, garbage collector, and execution context. Multiple isolates run within the same operating system process, separated by V8's security sandbox. Creating a new isolate takes less than 1 millisecond because there is no OS-level container to boot, no runtime to initialize, and no dependencies to load.
Global deployment:
Workers deploys to all 310+ Cloudflare data centers simultaneously. When you run wrangler deploy, your code is pushed to every location worldwide within seconds. There is no region selection — every user, everywhere, hits the nearest Workers instance.
Resource limits:
| Resource | Free Plan | Paid Plan ($5/month) |
|---|---|---|
| Requests | 100,000/day | 10 million/month included |
| CPU time per request | 10ms | 30ms (50ms with automatic extension) |
| Wall-clock time | N/A (limited by CPU) | 30 seconds |
| Memory | 128 MB | 128 MB |
| Script size | 1 MB | 10 MB (after compression) |
| Environment variables | 64 | 128 |
| Subrequests (fetch) | 50 | 1,000 |
Companion services extend Workers beyond simple request handling:
| Service | Description |
|---|---|
| Workers KV | Global key-value store, eventually consistent, optimized for reads |
| Durable Objects | Strongly consistent, single-threaded coordination primitives |
| R2 | S3-compatible object storage (zero egress) |
| D1 | SQLite database at the edge |
| Queues | Message queuing for async processing |
| Workers AI | ML inference at the edge (Llama, Stable Diffusion, etc.) |
| Hyperdrive | Connection pooling for external databases (Postgres, MySQL) |
| Vectorize | Vector database for AI/RAG applications |
| Workflows | Durable, multi-step execution (beta) |
Limitations to acknowledge: 128MB memory is restrictive for data-heavy workloads. No native Python, Java, Go, or .NET runtimes. No file system access. No TCP/UDP sockets (HTTP only via Fetch API, plus WebSockets and TCP via connect API). No native database drivers — you must use HTTP-based database protocols or Hyperdrive for connection pooling.
AWS Lambda: Container-Based Compute Engine
Lambda runs your code inside Firecracker microVMs — lightweight virtual machines purpose-built for serverless workloads. Each function invocation gets an isolated environment with a full operating system, language runtime, and file system.
Language runtimes:
Lambda natively supports Node.js, Python, Java, .NET, Go, and Ruby. Custom runtimes allow any language via the Lambda Runtime API. You can also deploy functions as container images (up to 10GB), bringing any language, any dependencies, and any system libraries.
Resource limits:
| Resource | Limit |
|---|---|
| Memory | 128 MB – 10,240 MB (10 GB) |
| CPU | Proportional to memory (2 vCPUs at 1,769 MB, 6 vCPUs at 10 GB) |
| Execution timeout | 15 minutes |
| Package size | 50 MB (zipped) / 250 MB (unzipped), 10 GB (container image) |
| Temporary storage (/tmp) | 512 MB – 10,240 MB |
| Concurrent executions | 1,000 (default, can be increased) |
| Payload size | 6 MB (sync) / 256 KB (async) |
Key features:
- SnapStart for Java: pre-initializes the JVM and snapshots the memory state, reducing Java cold starts from 5-10 seconds to ~200ms
- Provisioned Concurrency: keep a specified number of function instances warm, eliminating cold starts for a price ($0.000004646/GB-second idle)
- Lambda Layers: share libraries and dependencies across functions without including them in each deployment package
- Event source mappings: native integration with SQS, Kinesis, DynamoDB Streams, MSK, MQ for event-driven processing
- Lambda@Edge: run Node.js/Python at CloudFront's 13 regional edge caches (not all 600+ PoPs)
- CloudFront Functions: lightweight JavaScript at all CloudFront edge locations (very restricted: 1ms max, 2MB memory, no network)
- Lambda Function URLs: direct HTTPS endpoints without API Gateway
- Powertools for Lambda: official libraries for structured logging, tracing, metrics, idempotency, and validation
Lambda's depth is unmatched. The ecosystem of event sources, integration patterns, and operational tooling has had a decade to mature.
Google Cloud Functions: Two Generations, One Direction
Google Cloud Functions exists in two generations, and the distinction matters:
1st gen is a simple event-driven function runtime. It supports Node.js, Python, Go, Java, .NET, Ruby, and PHP. Functions respond to HTTP requests or events from Google Cloud services (Pub/Sub, Cloud Storage, Firestore). It is the simplest serverless option on any cloud — write a function, deploy it, done.
2nd gen is built on Cloud Run — Google's container-based serverless platform. This means 2nd gen Cloud Functions are actually containers under the hood, giving them:
| Feature | 1st Gen | 2nd Gen |
|---|---|---|
| Max memory | 8 GB | 32 GB |
| Max timeout | 9 minutes (HTTP) / 10 min (event) | 60 minutes |
| Concurrency | 1 request per instance | Up to 1,000 concurrent requests per instance |
| Min instances | 0 | 0 (configurable minimum) |
| Traffic splitting | No | Yes (via Cloud Run revisions) |
| Event sources | Native triggers | Eventarc (unified event routing) |
| VPC connectivity | Serverless VPC Access | Direct VPC Egress |
2nd gen's concurrency model is a significant advantage. While Lambda processes one request per function instance (requiring more instances for parallel requests), Cloud Functions 2nd gen can handle up to 1,000 concurrent requests per instance — dramatically reducing cold starts and improving resource efficiency.
Cloud Functions for Firebase provides a streamlined experience for mobile/web backend development, with native triggers for Firestore, Realtime Database, Authentication, and Cloud Storage events.
Azure Functions: Most Flexible Hosting Model
Azure Functions distinguishes itself not through runtime innovation but through hosting flexibility and orchestration capabilities.
Hosting plans:
| Plan | Scaling | Cold Starts | Max Memory | Max Timeout | Price Model |
|---|---|---|---|---|---|
| Consumption | Auto (0 to N) | Yes (500ms-15s) | 1.5 GB | 10 minutes | Per-execution |
| Flex Consumption | Auto with always-ready instances | Reduced | 4 GB | Configurable | Per-execution + always-ready |
| Premium | Auto (1 to N, pre-warmed) | Minimal | 14 GB | Unlimited | Per-second + min instances |
| Dedicated | Manual/auto (App Service) | None | Per VM | Unlimited | Per VM (App Service pricing) |
| Container Apps | Auto (0 to N) | Container startup | Per container | Unlimited | Per-second |
This flexibility means Azure Functions can serve as a true serverless function (Consumption plan), a pre-warmed always-ready service (Premium), or a traditionally deployed application (Dedicated) — all using the same code and programming model.
Durable Functions is Azure's unique differentiator:
Durable Functions is an extension that lets you write stateful workflows using code. Instead of defining state machines in JSON (like AWS Step Functions), you write orchestrator functions in C#, JavaScript, Python, or Java using familiar async/await patterns:
// Azure Durable Functions orchestrator
const df = require("durable-functions");
module.exports = df.orchestrator(function* (context) {
// Fan-out: run multiple activities in parallel
const tasks = [];
tasks.push(context.df.callActivity("ProcessOrder", order1));
tasks.push(context.df.callActivity("ProcessOrder", order2));
tasks.push(context.df.callActivity("ProcessOrder", order3));
// Fan-in: wait for all to complete
const results = yield context.df.Task.all(tasks);
// Human interaction: wait for approval (up to 72 hours)
const approval = yield context.df.waitForExternalEvent("ApprovalEvent", 72 * 60 * 60);
if (approval.approved) {
yield context.df.callActivity("FinalizeOrders", results);
}
});
This code handles fan-out/fan-in parallelism, human interaction patterns, retries, and timeouts — all within a single function. The Durable Functions framework manages checkpointing, replay, and state persistence. AWS Step Functions achieves similar outcomes but with a JSON state machine definition that is separate from your code.
Bindings are another Azure Functions innovation: declarative input/output connections to Azure services. Instead of writing SDK code to read from a queue and write to a database, you declare bindings in configuration:
{
"bindings": [
{ "type": "queueTrigger", "name": "order", "queueName": "orders" },
{ "type": "cosmosDB", "name": "document", "direction": "out", "databaseName": "orders" }
]
}
The runtime handles connection management, serialization, and error handling. This reduces boilerplate significantly for integration-heavy functions.
Language support is the broadest: C#, JavaScript, TypeScript, Java, Python, PowerShell, Go, Rust, and any language via custom handlers.
Cold Starts: The Real Numbers
Cold starts are the most discussed and most misunderstood aspect of serverless computing. Here is what actually happens:
What Causes Cold Starts
A cold start occurs when there is no warm function instance available to handle a request. The platform must:
- Allocate a compute environment (container/microVM or isolate)
- Download your code and dependencies
- Initialize the language runtime
- Run your initialization code (module imports, connection establishment)
- Execute the handler
Steps 1-4 are the cold start. Workers eliminates steps 1-3 by using V8 isolates instead of containers.
Measured Cold Start Times
Based on published benchmarks and community testing as of 2025-2026. Actual times vary by runtime, package size, and region.
| Scenario | Workers | Lambda (Node.js) | Lambda (Python) | Lambda (Java) | Cloud Functions 2nd gen | Azure Functions (Consumption) |
|---|---|---|---|---|---|---|
| Minimal function | <1ms | 80-150ms | 100-200ms | 800ms-3s | 200-500ms | 500ms-2s |
| With dependencies | <5ms | 150-300ms | 200-500ms | 2-5s | 500ms-1.5s | 1-3s |
| Large package | <10ms | 300-800ms | 500ms-1s | 3-10s | 1-3s | 2-5s |
| With VPC | N/A | +200-500ms (improved) | +200-500ms | +200-500ms | +100-300ms | +1-3s |
| Warm invocation | <0.5ms | 1-5ms | 1-5ms | 1-5ms | 5-20ms | 5-20ms |
Why Workers Has No Cold Starts
The phrase "no cold starts" sounds like marketing, but it is architecturally accurate. Here is why:
A V8 isolate is created within an already-running V8 process. There is no container to boot, no OS to initialize, no runtime to load. The isolate creation itself takes less than 1 millisecond. Your code is already cached at the edge location (it was pushed there at deploy time). Module instantiation in V8 is measured in microseconds for typical Workers scripts.
The result: the difference between a "cold" and "warm" Workers invocation is less than 5 milliseconds, which is within the noise of network latency. In practical terms, there is no user-perceptible cold start.
The Cost of Eliminating Cold Starts on Hyperscalers
If cold starts are unacceptable on Lambda, you have two options:
Provisioned Concurrency: Lambda keeps a specified number of function instances initialized and ready. Cost: $0.000004646/GB-second for idle provisioned instances, plus the regular invocation charges when they execute. For a 512MB function with 10 provisioned instances, this costs approximately $60/month just to keep them warm — before any invocations.
SnapStart (Java only): Lambda pre-initializes the JVM and takes a memory snapshot. Subsequent cold starts restore from the snapshot instead of re-initializing, reducing Java cold starts from 5-10 seconds to ~200ms. Free to use, but only available for Java.
On Cloud Functions 2nd gen, minimum instances keep instances warm. On Azure Functions, the Premium plan provides pre-warmed instances. Both add cost relative to the pure pay-per-execution model.
Workers' architectural advantage: zero cold starts are free. There is no premium tier, no provisioned capacity, no warm-up strategy required.
Programming Model Differences
The Same API Endpoint, Four Ways
To illustrate the programming model differences, here is a simple JSON API endpoint that reads a query parameter and returns a response:
Cloudflare Workers:
export default {
async fetch(request) {
const url = new URL(request.url);
const name = url.searchParams.get("name") || "World";
return new Response(JSON.stringify({ message: `Hello, ${name}!` }), {
headers: { "Content-Type": "application/json" },
});
},
};
AWS Lambda (Node.js with Function URL):
export const handler = async (event) => {
const name = event.queryStringParameters?.name || "World";
return {
statusCode: 200,
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ message: `Hello, ${name}!` }),
};
};
Google Cloud Functions (2nd gen):
const functions = require("@google-cloud/functions-framework");
functions.http("hello", (req, res) => {
const name = req.query.name || "World";
res.json({ message: `Hello, ${name}!` });
});
Azure Functions (Node.js v4 model):
const { app } = require("@azure/functions");
app.http("hello", {
methods: ["GET"],
handler: async (request, context) => {
const name = request.query.get("name") || "World";
return {
jsonBody: { message: `Hello, ${name}!` },
};
},
});
The differences are subtle in this simple example but reveal important philosophical distinctions:
- Workers uses the Web Standards API (Request/Response, URL, fetch). If you know how to write a Service Worker, you know how to write a Worker. The mental model is "intercept an HTTP request and return an HTTP response."
- Lambda uses an event/context model. The function receives a structured event object and returns a structured response. The mental model is "process an event and return a result."
- Cloud Functions uses an Express-like model (req/res). The mental model is "handle an HTTP request like a Node.js web server."
- Azure Functions uses a trigger/binding model. The HTTP handler is registered declaratively. The mental model is "wire up inputs and outputs to a handler."
Where the Models Diverge
For simple HTTP handlers, all four are adequate. The differences become significant for:
Complex applications with routing:
Workers: Use itty-router, Hono, or other lightweight routers — or simply parse the URL in your fetch handler. The Workers ecosystem favors small, composable tools.
Lambda: Use API Gateway for routing (path-based, method-based), or handle routing within your Lambda function. Framework options include Serverless Framework, SAM, SST, and Architect.
Cloud Functions: Each function typically handles one route. For multi-route APIs, use Cloud Endpoints, API Gateway, or deploy multiple functions behind a load balancer — or use Cloud Run directly for a full web server.
Azure Functions: Each function handles one trigger. For REST APIs, define multiple functions with HTTP triggers or use Azure API Management for routing, versioning, and policies.
State management:
| Platform | Key-Value | SQL | Coordination | Files |
|---|---|---|---|---|
| Workers | KV (global, eventual consistency) | D1 (SQLite, edge) | Durable Objects (strong consistency) | R2 (object storage) |
| Lambda | DynamoDB, ElastiCache | RDS, Aurora | Step Functions, SQS | S3 |
| Cloud Functions | Memorystore, Firestore | Cloud SQL, Spanner | Workflows, Pub/Sub | GCS |
| Azure Functions | Cosmos DB, Redis Cache | SQL Database | Durable Functions, Service Bus | Blob Storage |
Workers' built-in state primitives (KV, D1, Durable Objects) are notable because they run on the same network without cross-service network hops. Durable Objects in particular solve a problem that is difficult on other platforms: strongly consistent, single-threaded state coordination at the edge — useful for rate limiting, leader election, WebSocket rooms, and real-time collaboration.
Ecosystem and Integration
| Capability | Workers | Lambda | Cloud Functions | Azure Functions |
|---|---|---|---|---|
| Built-in storage | KV, R2, D1 | Need S3, DynamoDB | Need GCS, Firestore | Need Blob, Cosmos DB |
| Relational database | D1 (SQLite), Hyperdrive (Postgres proxy) | RDS, Aurora (same-VPC) | Cloud SQL, AlloyDB | SQL Database, Cosmos DB |
| Message queue | Queues | SQS, SNS, EventBridge | Pub/Sub, Eventarc | Service Bus, Event Grid |
| AI/ML inference | Workers AI (on-network) | Bedrock, SageMaker | Vertex AI | Azure OpenAI, Azure AI |
| Orchestration | Workflows (beta) | Step Functions | Workflows | Durable Functions |
| API gateway | Built-in (routes/custom domains) | API Gateway, ALB, Function URLs | API Gateway, Cloud Endpoints | API Management, Function URLs |
| Cron/scheduled | Cron Triggers | EventBridge Scheduler | Cloud Scheduler | Timer trigger |
| WebSockets | Yes (native, + Durable Objects) | Via API Gateway WebSocket | No | Via SignalR Service |
| Observability | Tail Workers, Logpush, Analytics Engine | CloudWatch, X-Ray | Cloud Logging, Cloud Trace | Application Insights |
| Local development | Miniflare (full local emulation) | SAM local, LocalStack | Functions Framework | Azure Functions Core Tools |
| IaC | Wrangler, Terraform, Pulumi | CloudFormation, SAM, CDK, Terraform | Terraform, gcloud | ARM, Bicep, Terraform |
| CI/CD | Wrangler in any CI, Workers Builds | CodePipeline, CodeDeploy | Cloud Build, Cloud Deploy | Azure DevOps, GitHub Actions |
Lambda's ecosystem is the most mature by a wide margin. The breadth of event sources (200+ AWS services can trigger Lambda), the depth of integration patterns, and the size of the community create a compounding advantage. If you are building event-driven architectures within AWS, Lambda is the gravitational center.
Workers' ecosystem is smaller but architecturally cohesive. Every companion service (KV, R2, D1, Durable Objects, Queues, AI) runs on the same network with zero data transfer cost and minimal latency. The trade-off is fewer integration options — Workers cannot natively trigger on S3 events, DynamoDB streams, or SQS messages.
Pricing Comparison
Prices as of February 2026. All prices in USD.
Per-Request Pricing
| Dimension | Workers (Paid) | Lambda | Cloud Functions 2nd gen | Azure Functions (Consumption) |
|---|---|---|---|---|
| Monthly included | 10M requests | 1M requests | 2M invocations | 1M executions |
| Per request | $0.30/million | $0.20/million | $0.40/million | $0.20/million |
| Free tier | 100K/day (free plan) | 1M/month (always free) | 2M/month (always free) | 1M/month (always free) |
Compute Pricing
| Dimension | Workers | Lambda | Cloud Functions 2nd gen | Azure Functions |
|---|---|---|---|---|
| Billing unit | CPU milliseconds | GB-seconds | GB-seconds, GHz-seconds | GB-seconds |
| Included | 30M CPU-ms/month | 400,000 GB-sec/month | 400,000 GB-sec/month | 400,000 GB-sec/month |
| Price | $0.02/million CPU-ms | $0.0000166667/GB-sec | $0.0000025/GB-sec, $0.00001/GHz-sec | $0.000016/GB-sec |
| Memory | 128 MB (included) | 128 MB – 10 GB (choose) | 128 MB – 32 GB (choose) | 128 MB – 1.5 GB (Consumption) |
| Min charge | $5/month (paid plan) | $0 | $0 | $0 |
The CPU Time vs Wall-Clock Time Distinction
This is the most important pricing nuance in the comparison. Workers bills for CPU time. Lambda bills for wall-clock time (duration).
What this means: if your function makes an API call that takes 200ms to respond, and your function uses 5ms of CPU before and after that call:
- Workers charges for: 10ms of CPU time. The 200ms waiting for the API response costs nothing.
- Lambda charges for: 210ms of duration (the full wall-clock time including the wait).
For I/O-heavy workloads (API proxies, data aggregation, fan-out patterns), Workers is dramatically cheaper because most of the execution time is spent waiting for network responses, not computing.
For CPU-heavy workloads (image processing, video transcoding, ML inference, data transformation), Lambda is more cost-effective because the CPU usage equals the duration — and Lambda provides much more memory and CPU power.
Cost at Scale
Scenario 1: API proxy (I/O-heavy) 100M requests/month, 5ms average CPU time, 200ms average wall-clock time, 128MB memory
| Provider | Monthly Cost |
|---|---|
| Workers | ~$32 (requests + CPU time) |
| Lambda | ~$53 (requests + GB-seconds at 128MB for 200ms each) |
| Cloud Functions | ~$79 (invocations + GB-seconds + GHz-seconds) |
| Azure Functions | ~$53 (executions + GB-seconds) |
Workers wins by ~40% because you do not pay for the 195ms of I/O wait per request.
Scenario 2: Image processing (CPU-heavy) 10M requests/month, 500ms average CPU time, 500ms average wall-clock time, 1GB memory
| Provider | Monthly Cost |
|---|---|
| Workers | Not viable (128MB memory insufficient for image processing) |
| Lambda | ~$85 (requests + GB-seconds at 1GB for 500ms each) |
| Cloud Functions | ~$52 (invocations + GB-seconds + GHz-seconds) |
| Azure Functions | ~$85 (executions + GB-seconds) |
Workers is not suitable here due to the 128MB memory limit. Lambda and Azure Functions are comparable. Cloud Functions 2nd gen has lower compute pricing.
Scenario 3: Scheduled background jobs 1,000 executions/month, 120 seconds average, 2GB memory
| Provider | Monthly Cost |
|---|---|
| Workers | Not viable (30-second limit) |
| Lambda | ~$4 (minimal at this scale) |
| Cloud Functions | ~$3 |
| Azure Functions | ~$4 |
Workers' 30-second execution limit makes it unsuitable for long-running jobs. All three hyperscaler options are viable and cheap at this scale.
Calculate Your Costs
Use the calculator below to estimate costs for your specific workload:
Serverless Compute Cost Calculator
Compare serverless function costs across providers.
Estimates based on published pricing as of February 2026. Actual costs may vary by region, commitment, and usage patterns.
Edge vs Region: The Fundamental Architecture Question
This is the strategic question that underlies the entire comparison. Workers runs at the edge (310+ locations). Lambda, Cloud Functions, and Azure Functions run in specific cloud regions (typically 20-30 regions per provider).
When Edge Wins
User-facing API responses. If your API serves users globally and the response can be computed at the edge (from cached data, KV, D1, or R2), Workers provides the lowest possible latency — the response originates from the nearest of 310+ locations.
Authentication and authorization. JWT validation, session checks, API key verification — these are lightweight compute operations that benefit from running as close to the user as possible. Every millisecond of auth latency adds to every subsequent request.
A/B testing and personalization. Splitting traffic, modifying responses based on user segments, or inserting personalized content works best at the edge before the request reaches origin infrastructure.
Geographic routing and content localization. Modifying responses based on user location (language, currency, content variants) is a natural edge workload.
When Regions Win
Database-heavy workloads. If your function queries a database in us-east-1, running the function in us-east-1 gives you ~1ms round-trip to the database. Running it at a Cloudflare edge location 200ms away from your database adds 200ms of latency per query. Cloudflare's Hyperdrive (connection pooling and caching for Postgres) and Smart Placement (automatically running Workers near their backend dependencies) partially address this, but the physics of network latency remain.
Large compute workloads. Image processing, video transcoding, ML inference, and data transformation need more than 128MB of memory and more than 30 seconds of execution time. These belong in regions with powerful compute instances.
Complex multi-service orchestration. If your function calls five AWS services in sequence (DynamoDB, SQS, S3, SES, SNS), running it in the same AWS region eliminates cross-service latency. Running it at the edge would add hundreds of milliseconds per service call.
Compliance and data residency. Some workloads require that compute happens in a specific geographic jurisdiction. While Workers offers jurisdiction restrictions, Lambda's region model provides more granular control (e.g., specifically eu-central-1 for German data sovereignty requirements).
The Hybrid Approach
The most sophisticated architectures use both:
- Edge for request handling: auth, routing, caching, personalization, static content
- Region for heavy processing: database queries, business logic, background jobs, ML inference
Cloudflare Workers can proxy requests to regional backends (Lambda, Cloud Run, Azure Functions) after performing edge operations. This "edge router + regional compute" pattern captures the benefits of both models.
Decision Framework
Choose Cloudflare Workers When:
- Global latency matters — your users are distributed worldwide and every millisecond counts
- Cold starts are unacceptable — real-time APIs, interactive applications, WebSocket endpoints
- I/O-heavy workloads — API aggregation, proxy, data fetching where CPU time is a fraction of wall-clock time
- You want integrated edge state — KV, D1, Durable Objects, R2 on the same network
- Simple deployment is valued —
wrangler deploypushes globally in seconds - The trade-offs are acceptable — 128MB memory, JS/TS/WASM only, 30-second limit
Choose AWS Lambda When:
- Ecosystem depth matters — 200+ AWS service integrations, the largest serverless community
- You need full language runtimes — Python with SciPy, Java with Spring, .NET with Entity Framework
- Complex event-driven architectures — SQS, Kinesis, DynamoDB Streams, EventBridge
- Heavy compute — up to 10GB memory, 15-minute execution, container image deployments
- You are already on AWS — Lambda is the natural compute layer for S3, DynamoDB, API Gateway workflows
Choose Google Cloud Functions When:
- GCP-native event processing — Pub/Sub, Firestore, Cloud Storage triggers via Eventarc
- Long-running functions — 2nd gen supports up to 60-minute execution
- High concurrency per instance — 2nd gen handles up to 1,000 concurrent requests per instance, reducing cold starts
- Firebase integration — Cloud Functions for Firebase is the most streamlined mobile backend
- You want a simpler serverless model — fewer configuration options than Lambda, fewer surprises
Choose Azure Functions When:
- Orchestration is core — Durable Functions provides code-based workflow orchestration that no other platform matches
- Hosting flexibility — Consumption, Premium, Dedicated, and Container Apps hosting from the same codebase
- .NET/C# is your primary language — Azure Functions has the best .NET experience
- Hybrid deployment — Azure Functions on Kubernetes (KEDA) runs on-premises or in any cloud
- Enterprise Microsoft ecosystem — Azure AD, Azure DevOps, Application Insights integration
The Honest Assessment
Workers represents a genuinely different approach to serverless computing. It is not a "better Lambda" — it is a different thing. The V8 isolate model makes architectural trade-offs that Lambda's container model does not: you get zero cold starts and global deployment, but you give up full language runtimes, large memory, and long execution.
For web-facing workloads — APIs, websites, real-time applications, middleware — Workers' architecture is objectively superior in latency, cold start behavior, and cost efficiency. The 128MB memory and 30-second limit are rarely constraints for these workloads.
For backend processing — data pipelines, batch jobs, ML inference, image processing — Lambda (or Cloud Functions, or Azure Functions) is the right choice. More memory, more CPU, longer execution, deeper ecosystem integration.
The most important insight: these platforms are not mutually exclusive. Many production architectures use Workers for edge routing and real-time response handling while delegating heavy processing to Lambda or Cloud Run. Understanding when each model excels is more valuable than declaring a winner.
Cloudflare Workers' biggest long-term bet is not the isolate runtime itself — it is the ecosystem of edge services (KV, D1, R2, Durable Objects, Queues, AI) that together create a complete application platform at the edge. If that ecosystem continues to mature, the range of workloads that can run entirely on Workers expands significantly. That trajectory is worth watching regardless of which platform you choose today.