Computing at the edge
What moves to the edge, what cannot, and the constraints that make edge code a different runtime.
What actually belongs at the edge
intermediateThe edge stopped being a cache some time ago. Code now runs in the same locations that serve cached bytes, which means work can happen close to the user instead of at an origin that may be a continent away, and the interesting question is which work.
The clear wins are decisions that need little or no state. Routing, redirects, A/B assignment, geographic personalisation, request rewriting, authentication checks against a token that can be verified locally, and bot filtering. Each removes a round trip to origin for a decision that takes microseconds, and on a connection with a hundred millisecond round trip that is the entire perceived improvement.
The clear losses are anything that needs the database. If the code has to read the primary to decide, running it near the user has made the situation worse: the user's request now crosses the ocean from the edge rather than from a nearby origin, and it has added a hop. Edge compute is fast because it is near the user, and that advantage is spent the moment it has to talk to something that is not.
Between those sits the genuinely interesting case: serving a cached page and personalising it at the edge, so the invariant part is a cache hit for everyone and the variable part is filled in nearby. That is the technique that makes personalised pages cacheable at all, and it is why edge compute changed what a CDN is for rather than merely making it faster.
The rule to carry is that the edge is for decisions, not for data. A decision needs the request and a small amount of local information, and a decision made in three milliseconds near the user beats the same decision made in one millisecond a hundred milliseconds away, every time.
Moving computation near the user only helps when the computation does not immediately need something far away. That single test, does this need the database, sorts almost every candidate workload correctly and prevents the usual mistake of moving a data-dependent handler to the edge and making it slower.
This site runs its API in edge workers and keeps the learning material in prerendered static files precisely on that division: decisions and small stateful operations near the reader, and the large body of content served as bytes that need no computation at all.
What is the single most useful test for an edge workload?
A different runtime, with different rules
advancedEdge platforms do not run ordinary servers. They run many small isolated contexts inside a shared runtime, started per request in microseconds rather than as containers, which is what makes them cheap enough to place in hundreds of locations. That model buys the startup time and imposes constraints that surprise anyone porting existing code.
The limits are real and worth knowing in advance. CPU time per request is measured in milliseconds rather than seconds. Memory is tens of megabytes. The available APIs are web standard rather than the full runtime of the language, so a library depending on the filesystem or on raw sockets may simply not work. And the process does not persist, so nothing can be kept in memory between requests as though it were a server.
Statelessness is the constraint that shapes the design. There is no local disk and no reliable in-process cache, so state lives in a platform service: a key-value store with eventual consistency, an object store, a database designed to be reachable from many locations, or a coordination primitive that pins a piece of state to one place. Each has a latency and consistency profile that has to be chosen deliberately.
Data locality then becomes the central design question, because a globally distributed compute layer over a single-region database is a distributed system with a hundred fast front ends and one slow shared dependency. The patterns that work are reading locally from replicated storage, writing to a home region, and pushing anything genuinely global through a mechanism designed for it rather than through the database by accident.
None of this makes the edge unsuitable, it makes it a specific tool. Small, fast, stateless work with a nearby state store is what it does extremely well. A long-running job, a large in-memory model, or a handler that needs a transaction against a primary is what it does badly, and knowing the boundary is more valuable than any amount of tuning on the wrong side of it.
The edge is a different runtime rather than a nearer server: milliseconds of CPU, tens of megabytes, web-standard APIs and no persistence between requests. Those constraints are what make the model cheap enough to place everywhere, and they decide what can be moved there without a rewrite.
The isolate model, many lightweight contexts in one runtime rather than a container per tenant, is what removes cold starts and makes hundreds of locations economic. The constraints on CPU, memory and available APIs follow directly from that choice.
Why do edge platforms impose tight CPU and memory limits?
The edge as the security boundary
intermediateThe most valuable property of the edge is not speed, it is that hostile traffic can be refused before it reaches anything you own. A request absorbed in a location near its source never consumes origin capacity, never opens a database connection and never runs a line of your code, which is a different kind of protection from a service that handles the request efficiently.
Volumetric attacks make the argument by themselves. A distributed denial of service that would saturate an origin's link is spread across hundreds of locations, each seeing a fraction, and absorbed by capacity that exists anyway for legitimate traffic. No origin-side rate limiter helps with an attack that fills the pipe before arriving, because the damage is done upstream of anything you control.
The layer above that is deciding who is worth serving. Bot management, filtering by reputation, challenges for suspicious clients and blocking obviously malformed requests all belong here, because each is a decision needing only the request and some shared intelligence. Doing the same work at origin means paying for the connection and the compute to reject something you did not want.
Rate limiting at the edge is subtly better than at origin for a reason worth stating: the edge sees the whole picture. A limiter running on each origin instance sees only its own share of the traffic, so a limit of a hundred a minute becomes a hundred per instance, while the edge counts the caller across every location and applies the limit that was actually intended.
The mistake is treating the edge as sufficient. It is a filter, not an authorisation system, and anything reachable by a request that gets past it still needs its own checks, because a leaked origin address, an internal caller or a rule that is one release out of date will all bypass it. Defence in depth means the edge removes the volume and the origin still refuses what it should refuse.
Refusing traffic near its source is qualitatively different from handling it efficiently at origin, because the cost is paid by capacity that already exists for other reasons. The corollary is that the edge is a filter rather than a control: everything behind it still has to defend itself.
Large content networks absorb volumetric attacks by spreading them across hundreds of locations, which is capacity no individual origin could justify. The same distribution that makes them fast is what makes them able to soak up traffic nobody wants.
Why is rate limiting at the edge more accurate than at each origin instance?