How Cloudflare Scaled Postgres: SQL at the Edge

A look at how Cloudflare scaled Postgres. Cloudflare’s serverless Postgres puts a SQL database at the network edge, close to users, queries answered in single-digit milliseconds from anywhere. The architecture borrows from Neon and Turso: separate compute from storage, run compute at the edge, store pages and WAL segments centrally, and use read replicas backed by shared storage.

How Cloudflare serverless Postgres works: architecture diagram showing edge SQL proxy, query cache per region, connection pool, primary with WAL, and S3-style page store

How Cloudflare Scaled Postgres: The problem at scale

Postgres wasn’t designed for edge deployment. It’s a stateful server: long-lived connections, on-disk page cache, write-ahead log, MVCC tuples. Running it at the edge (300+ POPs) means either running a Postgres instance per POP (operational nightmare) or routing queries to a central primary (latency nightmare). Cloudflare’s bet is to split Postgres into compute (which can run anywhere) and storage (which can be centralized), then deploy thin compute at every edge POP.

The core architecture

When a Cloudflare Worker or external client queries the database, the request hits the Edge Proxy at the nearest Cloudflare POP, not the Postgres wire protocol (which requires a long-lived TCP connection), but SQL over HTTPS. The proxy parses the query, checks the per-region Query Cache for a hit, and either returns the cached result or forwards to the central primary via a pooled Connection Pool. The primary (a Neon-style architecture) runs Postgres compute against a storage layer backed by S3-like object storage: database pages are fetched on demand from object storage, and the WAL (write-ahead log) is shipped to object storage as segments. Read replicas can be created on demand: they share the same storage as the primary but apply WAL asynchronously.

Compute-storage separation is the architectural primitive

Traditional Postgres couples compute and storage: the Postgres process owns its data directory on local disk, caches pages in shared buffers, and writes WAL to local files. To scale horizontally, you’d need to replicate the entire stack per replica. Neon’s innovation (which Cloudflare’s product adapts) is to separate them: a “page server” fetches database pages from object storage on demand, the Postgres compute process talks to the page server as if it were local disk, and WAL is shipped to object storage immediately. This means read replicas are cheap: they share the same page server, just apply WAL with a slight delay.

Cloudflare’s addition: run the SQL proxy at every POP, cache per-region, pool connections back to the primary. A SELECT that returns the same rows for every user in a region is served from the edge cache without touching the primary.

The HTTPS-instead-of-wire-protocol choice

Standard Postgres uses a binary protocol over TCP port 5432. This works great for long-lived server-side connections (a backend service connecting to its database) but poorly for edge compute (which may have a sub-second total request budget and no way to hold a TCP connection open). Cloudflare’s edge accepts SQL over HTTPS: the worker sends the query as JSON in a POST request, the edge proxy translates to Postgres wire protocol internally, and the response comes back as JSON. The overhead is small relative to the network round-trips saved by serving from cache.

The one non-obvious insight

The hardest part isn’t compute-storage separation. It’s cache invalidation at the edge. If user A writes a row from a Worker in Frankfurt, and user B reads it from a Worker in Tokyo, the Tokyo edge cache needs to know the row changed. Cloudflare uses a combination of TTL-based cache expiry (aggressive, since the source of truth is the primary) and explicit invalidation on writes (the edge proxy tags cache entries by table, and writes invalidate the relevant tags). The trade-off: writes are slow (round-trip to primary), reads are fast (cache hit), and there’s a brief staleness window of a few hundred milliseconds globally. For most app workloads (read-heavy with occasional writes), this is the right trade.

Cloudflare’s serverless Postgres brings SQL to the edge by separating compute from storage (Neon-style), running thin SQL proxies at every POP, and accepting the cache-staleness trade-off that comes with edge caching. The pattern is the future of database serving for read-heavy apps with global users.