- Document Number
005
- Subject of Record
- CLOUDFLARE WORKERS ISN’T SERVERLESS ANYMORE
- Prepared By
- TULIO CUNHA
- Date Filed
- AUG 22, 2026
- Classification
- INTERNAL TECHNICAL MEMORANDUM
Cloudflare Workers Isn’t Serverless Anymore
SUBJECT BRIEF
How Cloudflare quietly turned a serverless function runtime into something closer to a programmable distributed application operating system — decomposing the server into composable capabilities across isolates, SQLite Durable Objects, Workflows, and Containers.

Opening
There is a very specific architecture people picture when you say serverless. A request arrives. A tiny function wakes up. It does some work. It talks to a database somewhere else. It returns a response. Then it disappears into the void.
request
↓
stateless function
↓
database / object storage / API
↓
responseThat mental model defined most of the serverless era.
AWS Lambda made it mainstream. Vercel Functions made it fashionable for web developers. Cloudflare Workers made it absurdly fast by replacing heavyweight execution environments with V8 isolates distributed across Cloudflare’s network.
But somewhere along the way, Workers stopped fitting inside that box.
Not because Cloudflare abandoned serverless.
Quite the opposite.
Cloudflare kept applying the serverless idea—you describe the application, the platform owns the machines—to workloads that serverless platforms traditionally told you not to run serverlessly:
State
Coordination
Long-lived execution
Background jobs
Queues
Relational databases
WebSockets
Containers
Full Linux environments
Processes
Filesystems
RPC
Agents with their own computers
Cloudflare still calls Workers a serverless platform, and technically it is correct. You still do not provision servers, patch operating systems, manage clusters, configure autoscaling groups, or decide which machine should execute an HTTP request.
And that distinction changes everything.
The headline is technically wrong
Let me get the annoying correction out of the way first.
Cloudflare Workers is still serverless.
There are servers. Obviously.
You just do not manage them.
That was always the useful definition of serverless, despite a decade of jokes about how “serverless still has servers.”
The operational contract remains intact:
your responsibility
────────────────────
code
application architecture
data model
business logic
Cloudflare's responsibility
───────────────────────────
machines
process scheduling
runtime provisioning
capacity
autoscaling
network placement
failover
infrastructure lifecycleThat is absolutely serverless.
The problem is that somewhere around 2016, serverless became both an operational model and an architectural stereotype.
And the stereotype was much narrower.
Serverless meant stateless functions. Short execution. No local disk. No durable memory. No reliable process identity. No long-lived coordination. No real background process. Anything substantial lived somewhere else.
The serverless function was just glue.
That architecture made sense because most early serverless platforms were fundamentally designed around isolated invocations. The function existed temporarily. Durable things did not.
That led to a generation of architecture diagrams that looked like someone spilled alphabet soup across AWS:
API Gateway
↓
Lambda
┌──┼─────────┐
↓ ↓ ↓
SQS DynamoDB S3
↓
Lambda
↓
Step Functions
↓
another LambdaPerfectly valid. Sometimes extremely effective.
But notice the underlying rule:
That rule no longer describes Cloudflare Workers.
Workers was weird from the beginning
Workers never really behaved like Lambda.
The name probably hurt the mental model. A Worker sounded like another function.
Underneath, however, Cloudflare made a fundamentally different runtime bet.
Workers runs JavaScript inside V8 isolates rather than assigning every workload its own container or virtual machine. Many isolates can coexist inside a process, making them dramatically lighter to create and switch between than conventional container-based isolation. Cloudflare built this architecture specifically because code needed to be available throughout a globally distributed network without requiring a warm container sitting everywhere waiting for traffic.
The practical result was strange if you came from conventional cloud infrastructure.
You did not deploy a server to São Paulo, another to Virginia, and another to Frankfurt.
You deployed code. Cloudflare figured out where it should execute. The network became part of the runtime.
That was the first important inversion:
| Machine-first | Invocation-first |
|---|---|
| Traditional Cloud: Choose region → Create compute → Attach network → Route users to compute. | Workers: Deploy application → Request enters network → Network chooses execution. |
Those look similar from far away. Architecturally, they are completely different starting points.
One begins with a machine. The other begins with an invocation.
For years, however, Workers still carried the classic serverless weakness: the execution model was brilliant, but the application model was incomplete. Sooner or later you needed state.
And state meant leaving the runtime.
Then Durable Objects arrived. That was where the story became much more interesting.
Durable Objects broke the stateless-function model
Durable Objects are one of those primitives that sounds unimpressive until the mental model clicks.
If you describe them as “stateful Workers,” you undersell them.
If you describe them as “Cloudflare Redis,” you are simply wrong.
A Durable Object gives an application a globally addressable unit of stateful compute.
For a given object ID, Cloudflare provides a unique running object with strongly consistent transactional storage and routes requests targeting that ID to it. This makes the primitive useful not merely for persistence, but for coordination.
Think:
room:abc123
document:42
match:arsenal-v-chelsea
user:981
agent:customer-support-17
cart:7f92Each can have a place where its authoritative state and business logic meet.
That means problems that traditionally require some combination of:
application servers
Redis
distributed locks
pub/sub
WebSocket infrastructure
session affinity
database transactions
leader election
can sometimes collapse into one programming abstraction.
And in 2026, the primitive became considerably more serious.
Cloudflare now recommends SQLite-backed Durable Objects for new applications, and as of July, accounts without legacy KV-backed namespaces can no longer create new KV-backed Durable Object namespaces. Each SQLite-backed object gets private transactional storage, SQL, synchronous KV access, alarms, full-text search support, and point-in-time recovery for the previous 30 days.
That produces a very different object from the “ephemeral serverless function”:
Traditional function
request
↓
compute
↓
remote database
Durable Object
request
↓
stateful compute
↕
local SQLiteCloudflare's own documentation makes the distinction unusually explicit: D1 follows the familiar application-server-to-database architecture, while SQLite inside Durable Objects is a lower-level compute-with-storage building block where business logic can run on the same machine as the database.
That is not a small implementation detail. It changes where application boundaries naturally form.
A collaborative document does not necessarily need a stateless API server calling a database and broadcasting through Redis.
The document itself can become the unit of computation.
A multiplayer room can become the unit of computation.
An AI agent can become the unit of computation.
The runtime starts looking less like “functions” and more like an actor system somebody else operates for you.
Workers can be stateless. But the Workers platform absolutely is not limited to stateless architecture anymore.
Workflows broke the request lifecycle
The second sacred assumption of serverless was that work should be short.
Receive event. Execute. Finish.
If the job takes twenty minutes, waits for a customer approval, retries tomorrow, or needs to survive a process restart halfway through, congratulations: you have left Function Land.
Traditionally you solve that using queues, cron jobs, workflow engines, databases full of job states, Temporal, Step Functions, workers, or some homegrown state machine that eventually becomes the reason one engineer cannot take vacation.
Cloudflare Workflows attacks that boundary directly.
A Workflow can execute multiple durable steps, persist execution state, retry failures, wait for external events, sleep, and resume later. Cloudflare documents workflows that remain active across minutes, hours, days, or weeks. Individual workflow steps have no hard wall-clock limit, although CPU limits still apply; “unlimited wall time” does not mean infinite free computation.
That distinction matters. Consider a document-processing pipeline:
upload
↓
extract
↓
classify
↓
send for human approval
↓
wait 3 days
↓
approval arrives
↓
generate output
↓
publishIn the old function model, the pauses are your problem. You serialize progress. Store some job ID. Build retry semantics. Schedule the next execution. Make every step idempotent. Handle the case where the function dies between updating the database and publishing the next message.
You are effectively writing a miniature distributed execution engine.
With durable execution, the program itself becomes the state machine.
That is another inversion:
Traditional infrastructure: “Keep your process alive.”
First-generation serverless: “Your process will die. Persist enough information to reconstruct it.”
Durable execution: “Write the process as if it continues. The platform handles stopping and reconstructing it.”
That is conceptually much closer to programming a reliable distributed runtime than invoking a cloud function.
Queues brought back the background worker without the worker
Of course, not every asynchronous task deserves a durable workflow. Sometimes you just need a queue.
Send an email.
Generate thumbnails.
Update search indexes.
Call a flaky vendor API.
Batch analytics.
Fan events out to another system.
Cloudflare Queues provides guaranteed delivery, retries, batching, delays, dead-letter queues, Worker consumers, and HTTP pull consumers that can run outside Cloudflare entirely.
This sounds pedestrian because queues are ancient. That is precisely why it matters.
The impressive part of modern infrastructure is not inventing a futuristic replacement for every boring primitive. Sometimes the impressive part is making the boring primitives compose without forcing you back into machine management.
| Process Management | Capability Composition |
|---|---|
| Classic: Web Process → Queue Broker → Dedicated Job Worker Process (EC2/ECS). | Cloudflare: Worker → Native Queue → Consumer Worker (automatic scaling, zero machine identity). |
You still get the architectural separation. You stop caring which machine contains the consumer.
This theme repeats throughout the entire platform:
That is a much more interesting idea than “serverless scales automatically.”
Then Cloudflare put containers inside Workers
This is where the serverless label really starts bending.
Cloudflare Containers became generally available in April 2026. They run normal container images, support workloads requiring full Linux environments, arbitrary languages, native binaries, significant memory and disk, multiple CPU cores, SSH debugging, and existing software distributed as images. They scale down when unused and use active-CPU pricing.
If that sounds suspiciously like Cloudflare admitting that isolates cannot run everything, yes. Because they cannot. And that is fine.
The interesting decision was not adding containers. Every cloud has containers.
The interesting decision was how Cloudflare integrated them.
A Cloudflare Container is not presented as a parallel product universe where you leave Workers, enter a container service, configure ingress, wire networking, create credentials, expose an endpoint, and then somehow connect the two worlds again.
Containers are controlled by Workers.
The Container abstraction itself extends DurableObject. The Durable Object manages identity, routing, lifecycle, and persistent SQLite-backed state while the associated container executes your Linux image.
Read that architecture again:
Worker
↓
Durable Object
├── persistent SQLite state
├── routing / identity
└── Linux containerThat is genuinely fascinating.
Because Cloudflare did not bolt Kubernetes onto Workers. It absorbed container execution into the Workers programming model.
Your lightweight coordination logic stays in an isolate. When you actually need Linux, you invoke Linux. The container can then access Workers bindings—R2, D1, KV, Durable Objects, and other resources—through outbound handlers.
For the last decade, container architecture usually begins with: “What containers does my application consist of?”
Cloudflare is pushing toward: “Which parts of this operation actually require a container?”
That is almost the reverse question. And it produces a very different architecture.
Node.js is becoming compatibility, not identity
Another clue is what happened to Node compatibility.
Workers began as a Web-API-centric runtime: fetch, Request, Response, Streams, Web Crypto, WebSockets, WebAssembly.
The runtime deliberately did not pretend to be a generic Linux Node process. That was conceptually clean and occasionally painful.
The npm ecosystem assumes Node everywhere. Libraries import node:crypto, node:buffer, node:stream, node:http, filesystem APIs, and other Node built-ins, sometimes even when they only use a tiny portion of them.
Cloudflare spent years expanding compatibility.
Then, on August 4, 2026, it crossed an important line:
That does not turn Workers into Node. And Cloudflare shouldn't make that mistake.
Workers still has a different runtime model. What it does is remove a huge ecosystem tax from choosing that model.
The platform is effectively saying:
That is much healthier than making compatibility the architecture.
Service Bindings made the network optional
One of the strangest things traditional microservice architecture does is take two pieces of code that belong to the same system, place them behind HTTP servers, give them URLs, serialize everything into network payloads, authenticate the calls, send them over infrastructure, and then proudly announce that the services are decoupled.
Sometimes that separation is necessary. Sometimes it is distributed-systems cosplay.
Workers Service Bindings offer a fascinating middle ground.
One Worker can call another Worker without exposing it publicly. Services can communicate using HTTP semantics, or through Workers RPC by invoking methods that look like ordinary asynchronous function calls. Bound Workers execute on the same thread of the same Cloudflare server unless placement changes the execution topology, adding virtually zero network overhead.
Conceptually:
// Workers RPC via Service Binding: zero serialize/network penalty
const user = await env.USERS.getUser(id);instead of:
// Traditional HTTP microservice jump
await fetch("https://internal-users-service.example.com/users/" + id, {
headers: { Authorization: `Bearer ${internalSecret}` },
});The second architecture may still be correct if you need an independently addressable HTTP service. But if the boundary exists primarily for code organization, team ownership, deployment independence, or capability separation, why force the public Internet programming model into it?
Service Bindings preserve a service boundary without pretending every service needs to be a website.
And bindings more broadly are one of the most underrated pieces of Cloudflare's architecture:
R2 is not primarily a URL plus API key.
D1 is not primarily a database credential.
A Queue is not primarily a broker hostname.
A binding is both API surface and granted capability—effectively a permission and an API combined, without exposing underlying credentials to application code.
Again, this resembles an application runtime more than a collection of cloud services.
Even the database is becoming a placement problem
There is an obvious problem with “run compute everywhere.”
Your database probably does not live everywhere.
Move your function close to a user in Brazil while Postgres sits in Virginia and congratulations: you optimized the first millisecond of the request so you could spend the next 150 waiting for SQL.
Cloudflare increasingly treats this not as a reason to abandon globally distributed compute, but as a placement problem.
Workers can normally execute close to the incoming request. With Smart Placement, they can instead be positioned near a specific cloud region, host, API, or automatically selected upstream location to reduce total end-to-end latency for applications communicating with centralized backends.
Hyperdrive takes the same philosophy to existing Postgres and MySQL databases: maintaining connection pools close to the origin database, handling connection setup near Workers, and caching eligible read queries.
And if you want Cloudflare-native SQL, D1 supports read replicas across multiple regions through its Sessions API, preserving sequential consistency within a logical session while routing eligible reads to replicas.
In traditional deployments, location is encoded in the infrastructure:
app server → us-east-1
database → us-east-1
worker → us-east-1In the Cloudflare worldview, location becomes something the runtime can decide based on the operation: close to the user, close to the database, close to a Durable Object, or close to an available container.
The application stops having one obvious physical home.
The server is being decomposed into capabilities
This is the mental model that finally made the current Workers platform click for me.
A traditional server is a bundle:
CPU · Memory · Filesystem · Processes · Network Sockets
Local State · Runtime · Scheduler · Background Execution · Long-lived IdentityYou rent the whole bundle whether a particular operation needs all of it or not.
Containers improved the packaging. Serverless functions broke compute away from machine identity.
What Cloudflare is now doing is going further and decomposing the server itself into managed capabilities:
Need cheap request execution? Use an isolate.
Need authoritative state and coordination? Use a Durable Object.
Need SQL attached directly to that coordination unit? Use its SQLite storage.
Need normal relational application data? Use D1.
Need an existing Postgres database? Use Hyperdrive.
Need blob storage? Use R2.
Need deferred work? Use a Queue.
Need a process that survives for three days and pauses twice? Use a Workflow.
Need a full Linux environment? Start a Container.
Need arbitrary untrusted code? Use a Sandbox or Dynamic Worker.
Need two services to communicate? Bind them directly.
The result looks something like this:
┌─────────────┐
│ User │
└──────┬──────┘
↓
┌─────────────┐
│ Worker │
│ request CPU │
└──────┬──────┘
┌─────────────────┼──────────────────┐
↓ ↓ ↓
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ Durable Obj. │ │ Queue │ │ Workflow │
│ state + SQL │ │ async work │ │ durable exec │
└──────┬───────┘ └──────┬───────┘ └──────┬───────┘
│ │ │
↓ ↓ ↓
WebSocket Worker Container
clients when needed
┌─────────────────────────────────────┐
│ Data capabilities │
│ D1 · R2 · KV · Hyperdrive · etc. │
└─────────────────────────────────────┘The interesting part is the composition model.
Cloudflare is trying to make each infrastructure capability feel like part of one runtime rather than a product you discover by searching a 200-service catalogue.
That is why Workers increasingly feels less like Lambda and more like an operating system for distributed applications:
This does not mean “put everything on Cloudflare”
Now for the part platform fanboys usually skip.
This architecture is opinionated as hell. You are trading machine-level freedom for platform-level leverage:
Durable Objects are incredible when your domain naturally partitions into independent coordination units. They are terrible if you pretend every relational workload is an actor just because Cloudflare gave you actors.
D1 is convenient, but it is not a drop-in replacement for every Postgres workload.
Workflows reduce orchestration boilerplate, but durable execution changes how you reason about side effects and idempotency.
Node compatibility is dramatically better, but Workers is still not a generic Node process.
Containers are real containers, but Cloudflare's container orchestration model is deliberately not Kubernetes.
Smart Placement can optimize topology, but it cannot repeal the speed of light.
Service Bindings are excellent inside Cloudflare; they are obviously Cloudflare-specific.
And the more deeply you embrace Durable Objects, bindings, Workflows, D1, Queues, Containers, and platform-native RPC, the less truthful it becomes to say: “We could move this anywhere tomorrow.”
No. You could move the business logic. The architecture would require translation.
That is lock-in. But lock-in is not automatically bad:
Bad lock-in: We became dependent on proprietary complexity that gives us no proportional advantage.
Good lock-in: We deliberately adopted a proprietary primitive because it deleted an entire category of engineering work.
A Durable Object replacing Redis coordination, sticky sessions, WebSocket routing, a persistence layer, and a distributed lock may be worth considerably more than the theoretical portability you sacrificed.
The correct question is not “Is this portable?” It is:
Cloudflare's strongest argument in 2026 is that the exchange rate has become very good.
The most important architecture is choosing what _not_ to run in a container
Containers won cloud infrastructure because they are incredibly general.
That generality also creates architectural laziness:
Need a worker? Container.
Need cron? Container.
Need a WebSocket server? Container.
Need image processing? Container.
Need an API? Container.
Need one tiny background task that wakes up every six hours? Believe it or not, container.
Eventually the architecture becomes: everything → container → orchestrator.
This is perfectly defensible when the workload needs that environment. But it also means every application concern inherits container lifecycle, placement, networking, resource allocation, observability, scaling, image management, and orchestration overhead.
Cloudflare's model encourages the opposite strategy:
That leads to a clean execution hierarchy:
web-standard isolate
↓
stateful isolate
↓
durable execution
↓
full Linux containerThe application can move up and down that ladder depending on the operation.
`@cloudflare/computer` accidentally explains the entire strategy
In August 2026, Cloudflare released something that almost feels like the punchline to this article.
@cloudflare/computer is an early preview runtime for giving AI agents a programmable computer.
The obvious implementation would be giving every agent a sandboxed Linux container. Simple, but expensive.
Cloudflare chose something stranger: giving an agent a virtual filesystem backed by SQLite and dynamically choosing between different execution backends. Lightweight operations execute inside isolates through Dynamic Workers. Tasks requiring package managers, native binaries, or a complete Linux userland move into Cloudflare Containers.
┌───────────────┐
│ Agent │
└───────┬───────┘
↓
┌───────────────┐
│ Workspace │
│ SQLite files │
└───────┬───────┘
↓
What does this task need?
↙ ↘
lightweight full Linux
↓ ↓
V8 isolate ContainerThat is the Workers platform in miniature.
Do not ask: “Which server runs my application?”
Do not even ask: “Which container runs my application?”
Ask: “What capability does this operation require right now?”
Then let the platform map that requirement onto infrastructure.
Serverless won — which is why the word stopped being useful
There is an irony here.
The serverless movement succeeded so thoroughly that its original name is becoming boring.
Developers increasingly expect infrastructure products to scale automatically, recover automatically, route globally, hide machine provisioning, charge by usage, and deploy from source without requiring an operations ceremony.
Those are becoming table stakes.
“Serverless” therefore tells us less and less about what we can actually build:
Cloudflare Workers is serverless.
So is a tiny HTTP function.
So is a relational database.
So is a week-long durable workflow.
So is a stateful actor backed by SQLite.
So is a queue consumer.
And now, so is a Linux container that spins up when a Worker tells it to.
At some point the category becomes so broad that it stops describing the architecture. What matters instead is the runtime model.
The original abstraction was:
give us a function
we will run it near the userThe current abstraction is closer to:
give us an application
describe the capabilities each part requires
we will map them onto the networkThat is a much bigger ambition.
A better mental model
I would stop thinking of Workers as Cloudflare's serverless-functions product. That description is years out of date.
I would think of the platform as a distributed application runtime:
Workers is the lightweight compute layer.
Durable Objects provide identity, coordination, and colocated state.
D1 provides relational storage.
R2 provides blobs.
KV provides globally distributed read-heavy state.
Queues provide asynchronous messaging.
Workflows provide durable execution.
Service Bindings and RPC provide zero-latency application-internal communication.
Placement decides where compute should execute.
Containers provide machine-shaped escape hatches.
And the network connects all of it.
The machine is still there. The container is still there. The database server may still be there.
Cloudflare is not abolishing infrastructure. It is making infrastructure less visible as the primary unit of application design.
| The Historic Questions | The Runtime Question |
|---|---|
| Historic: "What servers do I need?" → "What managed services do I need?" → "What functions do I need?" | Modern: "What capabilities does my application need right now?" |
Because if Cloudflare gets this right, “serverless” will not mean that our applications became simpler.
It will mean something much better:
And maybe that was the point all along.
Key takeaways
REFERENCES // TRACEABLE SOURCES
- [r1]
- [r2]
- [r3]
- [r4]
- [r5]Cloud Computing without Containers-- Cloudflare
- [r6]SQLite in Durable Objects-- Cloudflare
- [r7]Cloudflare Workflows GA-- Cloudflare
- [r8]Cloudflare Containers GA-- Cloudflare
END OF MEMORANDUM