Connection · Interrupted

Something didn't load

Part of this page failed to reach you. Reload to try again — if it keeps happening, check your connection.

Skip to main content
Engineering18 min read

The Shift Zone: The Backend Is Becoming Software That Sleeps

I have watched state break the monolith, then microservices, then serverless — and I have spent months reading the changelogs that convince me the third break just got fixed. These are my notes on the 2024–2026 convergence of ephemeral compute and durable state, why the billing model is the tell, and the A/B experiment this post commits me to: rebuilding a problem I already solved in Spring Boot on the new substrate, with the numbers published either way.

All Posts
Listen to this post
0:00 / 0:00
2/4

Running software costs money. Full stop. Every architecture I have ever shipped is, underneath the diagrams, an answer to one question: am I paying for software to wait, or paying for software to work?

For twenty years my answer was "wait." A WAR file on a Java EE server behind Tomcat waits. A fleet of Spring Boot microservices on Kubernetes waits. The JVM sits warm, the heap sits allocated, the load balancer health-checks a process whose main job, most of the day, is to be ready. I have capacity-planned that waiting, autoscaled it, right-sized it, and paid for it on the first of every month regardless of what users did.

I have also watched the industry try to stop paying for it twice before. Both attempts stalled on the same rock: state. And the reason I am writing this post — the reason it opens a research series rather than closing an argument — is that I have spent months reading changelogs, pricing pages, and framework announcements, and I keep arriving at the same conclusion. The rock has been cleared. It is happening again, and this time the déjà vu comes with dates and prices attached.

Three waves, one recurring fracture

The arc I lived through is the arc most backend engineers of my generation lived through, so I will compress it — but I want to name what each wave broke, because the breakage is the pattern.

The first wave was the monolith, and it was better than its reputation. One deployable on an application server, one relational database, one transaction boundary. State was not a problem in that world — it was the product's core competency. BEGIN, mutate, COMMIT; the database enforced every invariant, and a rollback erased every mistake. What the monolith cost was agility and blast radius: one codebase, one release train, one outage domain. And it ran on capacity bought up front — servers sized for the traffic you hoped to have.

The second wave hit me around 2016, though its founding texts are earlier — James Lewis and Martin Fowler published the microservices article in March 2014, and the Netflix OSS stack plus Spring Cloud turned it into something a Java engineer could actually assemble. Breaking the giant platforms into smaller pieces bought independent deployment and team autonomy, and it broke state — for the first time. The transaction that used to span one database now spanned a network. I have written about the scars this left in detail: two-phase commit's blocking window that nobody puts in the diagram, the transactional outbox that everyone treats as a queue until Postgres buckles, idempotency as a four-part protocol because retries turned every write into a possible duplicate. None of those patterns existed in my monolith years because none of them were needed. They are the state primitives the second wave had to invent before it could be trusted with money.

Notice what the second wave did not change: the unit was smaller, but it still waited. Kubernetes — open-sourced in 2014, 1.0 in 2015 — industrialized the waiting. It made fleets of long-running processes schedulable, restartable, and observable, and it left the economics untouched: a pod is a process that runs whether or not anyone calls it.

The third wave started in the same season — AWS Lambda launched in November 2014 — and it aimed directly at the waiting. Shrink the unit from a service to a function invocation, bill it by the millisecond, scale it to zero between requests. I remember the excitement, and I remember what happened next: not much. Serverless settled into the edges of systems — image resizing, glue between managed services, cron jobs — and the core of every serious backend stayed on long-running servers. The reason was never the compute. It was that a function which forgets everything between invocations pushes all of its state into a database on every call, and the moment your domain needs a counter, a session, a workflow, a lock, or a WebSocket, you are hand-rolling distributed state machines over DynamoDB and paying latency for every byte of memory you used to get for free. The unit shrank; state broke; and this time the primitive that fixes it did not arrive on schedule. The wave stalled for most of a decade.

The pattern: the unit shrinks, state breaks, a primitive emerges

Laid side by side, the three waves run the same program. The deployment unit shrinks — server, then service, then invocation. The shrink breaks whatever state mechanism the previous generation relied on — the shared heap, then the shared transaction, then memory itself. The gap gets filled by new state primitives — the RDBMS transaction; then sagas, outboxes, and idempotency protocols; then, for the third wave, the durable-state layer that spent 2024–2026 going from research and beta into general availability. Once the primitive lands, the smaller unit becomes safe for core workloads, and the default shifts.

The diagram below is the whole thesis in one line: each wave's fracture point, and the primitive that sealed it.

I want to be precise about what "the primitive arrived" means, because that claim carries the post. So here is the landscape review — what actually shipped, with dates, while I was heads-down building Spring Boot services.

What shipped while I was building Spring Boot services

The evidence sorts into three shelves: the compute got ephemeral and cheap to interrupt, the state got durable and co-located, and a new generation of frameworks started assuming both.

The compute shelf: short-lived by default

Cloudflare Workers is the cleanest expression of the new unit. A Worker is not a container that boots — it is a V8 isolate created inside an already-running runtime, which is how Cloudflare eliminates the cold start of the virtual-machine model. The pricing is the interesting part: on the paid plan ($5/month minimum, 10 million requests included), you are billed for CPU time only — $0.02 per additional million CPU-milliseconds — and wall-clock time is free. A Worker awaiting a database response costs nothing while it waits. Egress costs nothing. The billing meter literally cannot see idleness. The ceilings are real (5 minutes of CPU per invocation, no arbitrary Linux binaries in the isolate), and 2025's Workers Containers extension — billed per 10 milliseconds of activity — shows Cloudflare pulling even container workloads into the same per-use frame.

Vercel spent 2025 rebuilding its functions runtime around the same idea. Fluid compute (announced February 2025, default for new projects since April) lets one function instance serve concurrent invocations instead of the Lambda-style one-sandbox-per-request model, and the Active CPU pricing that followed in June 2025 bills three meters: active CPU at $0.128/hour, provisioned memory at $0.0106/GB-hour, and $0.60 per million invocations. Their docs state the model plainly: CPU billing pauses while a request waits on I/O, and between requests you pay nothing at all.

AWS Lambda, the wave's origin, quietly fixed its worst number for people like me. The pricing is unchanged in shape — $0.0000166667 per GB-second on x86 (arm64 is 20% less), $0.20 per million requests, billed to the millisecond, hard-capped at 15 minutes — but SnapStart resumes a function from a cached Firecracker snapshot of the fully initialized runtime instead of re-running init. For Java — the runtime whose framework-heavy cold starts AWS itself describes as taking "several seconds" — SnapStart is free and cuts resume to sub-second. The JVM's cold-start tax, the single biggest reason my professional stack and serverless never mixed, has been engineered down to a rounding error.

Fly.io attacks from the opposite direction: instead of shrinking the runtime, make full VMs cheap to stop. A Fly Machine is a real microVM with a REST lifecycle; creating one takes low double-digit seconds, but starting a stopped one takes well under a second, which makes stop-on-idle a routine pattern rather than an outage. Billing is per-second while running — a shared-cpu-1x with 256 MB is about $1.94/month if it never sleeps — and a stopped Machine costs only its root filesystem storage at $0.15 per GB per 30 days. A server that sleeps for $0.15 a month and wakes in 300 milliseconds is not really a server in the sense I learned the word.

Even the Kubernetes world — the institutional home of the long-running process — is converging. Knative, the scale-to-zero request-driven layer on top of k8s, graduated as a CNCF project in October 2025. The difference, and it matters later in this post, is that Knative scales stateless pods to zero; it says nothing about where their state goes when they vanish.

The state shelf: durable objects, actors, and replayable workflows

The compute shelf alone would just re-run 2016's stall. The state shelf is what changed.

The intellectual ancestry is Microsoft Orleans, whose 2014 "virtual actor" paper — built to run Halo's backend — proposed actors that exist perpetually and activate on demand: you address an entity by identity, the runtime materializes it wherever there is capacity, and its state follows. Orleans stayed a .NET idea for years. What the current wave did is fuse virtual actors with edge runtimes and per-use billing.

Cloudflare Durable Objects is the fusion's flagship. A Durable Object is a globally unique, named instance of a class — single-threaded, so it processes one message at a time — with transactional storage co-located with the compute. Beta in 2020, GA in late 2021, and the piece that made me sit up: SQLite-backed storage went GA in April 2025, giving every object its own relational database up to 10 GB, accessed at memory speed because the data lives with the object. The economics follow the compute shelf: duration is billed only while the object is active in memory, and the WebSocket Hibernation API can evict an idle object while keeping its connections open — Cloudflare's own worked example prices 10,000 hibernating WebSocket connections at roughly $10/month versus about $417 without hibernation. An object that is not being talked to costs storage cents. This is the primitive serverless was missing in 2016: a place for state that scales to zero with the compute instead of fighting it.

The model is no longer proprietary to one vendor. Rivet Actors — launched publicly in December 2024, Apache 2.0, built in Rust — is an open-source implementation of the same shape: lightweight actors whose in-memory state persists automatically (SQLite or bring-your-own database), that sleep when idle and wake on demand, self-hostable as a single binary or run on their cloud, and deployable onto Vercel since October 2025. Their benchmarks claim actor cold starts around 20 milliseconds. I have not verified that number myself, and for this post it matters less than its order of magnitude: waking state is now measured in milliseconds, not JVM-seconds.

The workflow half of the state shelf is durable execution, and I have already paid my dues there. My notes on Restate cover the core mechanic and its cost: the runtime journals every step of a workflow, replays the journal after a crash, and in exchange demands determinism from your code — the line that broke replay in my six-step payment reconciliation was an innocent timestamp. Temporal industrialized this model (its founders built Cadence at Uber and forked it in 2019) and the market just priced the category's momentum: a $300 million Series D at a $5 billion valuation in February 2026, with OpenAI cited among the customers. Restate, from the creators of Apache Flink, compresses the same guarantee into a single Rust binary that pushes invocations to plain stateless handlers — including Lambda — and publishes p99 latencies under 170 milliseconds for a ten-step workflow. I compared the operational trade-offs of the category in DBOS vs Temporal — the short version is that durable execution stopped being exotic infrastructure and became something a single engineer can run.

Between durable objects for entity state and durable execution for workflow state, the two shapes of "state that survives the death of its compute" both went production-grade while the compute itself was learning to die cheaply. That coincidence is the shift zone.

The assumption shelf: frameworks that take all this for granted

The tell that a substrate has arrived is when new frameworks stop explaining it. Vercel introduced Eve in June 2026 — an open-source agent framework where an agent is a directory, deployed like any other project — and its architecture simply presumes the new stack: durable execution for long-running agent loops, sandboxed ephemeral compute for tool calls, human-in-the-loop approvals that park a workflow for hours without a process waiting anywhere. Eve is not itself a compute product; it is evidence of what its authors consider ambient. And the workload it serves is the purest case for the new economics: Vercel reports that agents now trigger about 29% of deployments on their platform, up from under 3% a year earlier — traffic that is bursty, unattended, and idle-heavy, the exact shape that makes paying-for-waiting indefensible.

The same assumption is reaching past the backend entirely. I wrote recently about local-first architecture, where the client holds the authoritative copy and the server demotes to a sync relay — and about hybrid logical clocks, the ordering primitive you reach for once no single server clock defines "later." Read against this post, those are the same shift seen from the client side: state migrating out of the always-on tier, with the data center keeping exactly the roles — relay, backup, refusal-writes, workflows — that the durable-state shelf implements. The picture composes: ephemeral functions at the edge of the request, durable objects and workflows where authority must live, clients owning what they can merge. Nothing in that picture waits.

The bill is the tell

Architecture papers can argue forever; pricing pages are falsifiable. So here is my question — pay up front for readiness, or pay per unit of work — with 2026 numbers on both sides.

The waiting baseline: an AWS Fargate task at 1 vCPU and 2 GB — a modest home for one Spring Boot service — costs about $36/month in us-east-1, traffic or no traffic. A t4g.medium EC2 instance is about $24.50. Now multiply the way real estates multiply: per service, per environment. Twenty microservices across dev, staging, and production is sixty always-on tasks — call it $2,100/month at Fargate prices — of which the overwhelming majority of vCPU-seconds are spent health-checking. That is the idle floor, and every capacity-planning exercise I have ever run was an attempt to shave it without getting paged.

The per-use column: the same request handled by a 1 GB Lambda costs $0.0000167 per GB-second plus $0.20 per million requests, metered to the millisecond. The arithmetic that matters: a 1 GB Lambda running flat out, 24/7, costs about $44/month — more than the Fargate task it would replace. Run it 10% of the time and it costs $4.40. Run it 1% of the time — the duty cycle of an internal tool, a webhook receiver, a report generator — and it costs 44 cents. Workers sharpens the same edge further by billing CPU-milliseconds only, so even wall-clock waiting inside a request is free; Vercel's Active CPU model does the same for the Node ecosystem. And the state tier now follows the same curve instead of fighting it: a Durable Object hibernates to storage cents, a stopped Fly Machine costs $0.15/GB of rootfs, a parked Restate workflow is rows in a log, not a thread in a pool.

The crossover is the honest part, and it cuts both ways.

Below the crossover — idle-heavy, spiky, unattended workloads — per-use pricing is not an optimization, it is a different category of bill. Above it — sustained, flat, predictable load — the old model wins on pure dollars: a Vercel function pinned at 100% active CPU runs about $109/month against that $36 Fargate task, and the Lambda arithmetic above already showed the same inversion. Pay-per-use is a bet on idleness. What makes the bet newly interesting is that the industry's workload mix is drifting toward the idle-heavy end — agents, webhooks, per-tenant services, long-tail APIs — at the same moment the primitives arrived. The economics and the mechanics are pushing the same direction. That is what a shift zone looks like from inside.

The strongest case against my own thesis

I distrust any argument of mine that has no good opponent, and this one has four.

The incumbent is not standing still. The long-running JVM of 2026 is not the one that pushed the industry to microservices. Virtual threads after JEP 491 removed the pinning problem and moved the bottleneck; Java 26 ships AOT object caching that attacks startup and warmup directly. A warm JVM at sustained utilization remains one of the cheapest, most boring ways to serve flat load ever built — and boring is a feature I have billed for. If your traffic is flat, the crossover chart already told you the answer, and it is not Lambda.

The lock-in gradient is steep. Durable Objects code runs on Cloudflare and nowhere else. Rivet is Apache 2.0 and self-hostable — that is precisely its pitch. Restate is BSL 1.1: free to self-host in production, source-available, each release converting to Apache 2.0 after four years, but not OSI-open today. Temporal is MIT, and self-hosting it means operating a multi-service cluster plus Cassandra or Postgres plus, usually, Elasticsearch. Every option prices exit differently, and after the local-first post I weigh exit cost as a first-class architectural property, not a procurement footnote.

The primitives have sharp edges I have already cut myself on. A single durable object is single-threaded — a hot entity becomes a throughput ceiling, the exact trade I measured in the actor-per-entity bake-off, where the actor model didn't remove the hard problem, it moved it into routing and rebalance correctness. Durable execution imposes determinism discipline that my Restate notes document line by line, and versioning a workflow that has thousands of in-flight executions is an operational skill the always-on world never needed. Hibernation-shaped APIs are mandatory, not optional: a Durable Object holding a non-hibernated WebSocket pays wall-clock duration around the clock, and "serverless" quietly becomes a server with worse ergonomics.

And the ceilings still exist: 15 minutes on Lambda, 5 CPU-minutes on Workers, egress fees that can dominate compute for data-heavy APIs everywhere except Cloudflare. None of this sinks the thesis. All of it bounds where the thesis applies — which is exactly what the next section is for.

The experiment: A/B-testing my own history

Reading is not evidence. So here is the commitment this post exists to make.

I have been building Spring Boot systems for years, and there is a problem in my past — one I have already solved once in that world, whose requirements and failure modes I know intimately — that I am going to build again on the new substrate: ephemeral compute for the request path, durable objects or actors for entity state, durable execution for the workflows. Call the original architecture A and the rebuild B. I am deliberately not naming the problem yet; the next post in this series introduces it, its invariants, and the original design as it actually was, before B gets a line of code.

What I will hold constant: identical functionality, identical correctness requirements, and a full test suite on both sides — including the concurrency and retry tests, because idempotency under retries is where architectures go to get caught lying.

What I will measure, in public, with the method shown:

  • Cost under three traffic shapes — idle-heavy, spiky, and sustained — because the crossover chart above is a hypothesis until it has my workload's numbers on it.
  • Latency, p50 and p99, including the cold paths — SnapStart resumes, actor wake-ups, and workflow replays included, not excluded as warm-up noise.
  • Operational surface — what can page me at 3 a.m. in each architecture, and how much of each system I must understand to fix it.
  • State correctness under failure injection — kill the process mid-workflow, race the concurrent writes, and compare what each model does by construction versus by my own discipline.
  • Exit cost — what it would take to move each build to a different provider, measured in changed lines and changed assumptions.

If B loses, the series will say so plainly — a negative result against my own thesis is still a result I can build on. But the pattern has run three times in my career, and each time the engineers who recognized the zone early spent the following five years ahead of the ones who waited for permission.

The takeaways I am carrying into part two:

  • The unit of backend deployment shrinks in waves, and each wave breaks state before a new primitive makes the smaller unit safe. The primitive for the serverless wave — durable objects, actors, durable execution — shipped between 2024 and 2026.
  • The billing model is the architecture signal: when the meter stops charging for idleness (CPU-ms billing, hibernation, stopped machines at storage cost), the platform is telling you what unit it wants you to ship.
  • Pay-per-use is a bet on idleness. Take it for spiky, unattended, long-tail, per-tenant workloads; refuse it for flat sustained load, where a warm JVM remains the honest winner.
  • Exit cost is a first-class property now: the same capability spans a proprietary edge (Durable Objects), Apache 2.0 self-hosting (Rivet), BSL (Restate), and MIT-with-operational-weight (Temporal).
  • Trust the A/B, not the manifesto — mine included. That is what the rest of this series is for.

Further reading

Read next

Still here? You might enjoy this.

Nothing close enough — try a different angle?

Was this helpful?

Leave a rating or a quick note — it helps me improve.