How Supabase Built a Postgres Pooler to Survive Massive Traffic Spikes
Imagine this: your startup just launched, a celebrity tweets about your app, and within 60 seconds, 50,000 users try to log in…
How Supabase Built a Postgres Pooler to Survive Massive Traffic Spikes
Imagine this: your startup just launched, a celebrity tweets about your app, and within 60 seconds, 50,000 users try to log in simultaneously. Your application servers scale up effortlessly, but then your database keels over and dies.
Why? Because PostgreSQL, the world’s most robust relational database, has a dirty little secret: it hates concurrent connections.
Every new connection to Postgres forks a new OS process. Give it 100 connections, and it runs like a dream. Give it 5,000, and it will exhaust your CPU in a storm of context-switching and memory starvation before it can even execute a single query.
To solve this, you need a connection pooler. For years, PgBouncer was the undisputed king. But when you are Supabase — hosting databases for hundreds of thousands of tenants, you need something more. You need a pooler that is multi-tenant, highly available, and capable of absorbing meteoric traffic spikes without breaking a sweat.
Enter Supavisor, Supabase’s open-source, multi-tenant Postgres connection pooler. It’s written in Elixir and runs on the Erlang VM (BEAM).
In this post, we are going to crack open Supavisor and explore its internals. We’ll look at how it works, and exactly why the Erlang VM makes it uniquely qualified to handle massive concurrency spikes.

The Core Architecture: How Supavisor Works
At its heart, Supavisor acts as a reverse proxy for the PostgreSQL wire protocol. It speaks Postgres to both the client (frontend) and the database (backend).
Here is how it handles the flow of data:
1. Transaction Pooling Mode
Like PgBouncer, Supavisor primarily operates in “transaction pooling” mode. When a client connects, Supavisor authenticates them. But instead of holding a dedicated database connection open for the client’s entire session, Supavisor does this:
- Client sends a query.
- Supavisor grabs an available server connection from the pool.
- Supavisor routes the query to Postgres.
- Postgres returns the result.
- Supavisor passes the result to the client and immediately returns the connection to the pool.
This allows 10,000 idle or slow clients to share a pool of, say, 100 actual Postgres connections.
2. Multi-Tenancy at Scale
Supabase hosts thousands of distinct databases. Supavisor is designed to manage pools for all of them simultaneously.
When a connection comes in, Supavisor identifies the tenant (usually via SNI or a specific connection string format). It looks up the tenant’s routing information and credentials, and routes them to their specific backend Postgres instance.
3. Native Protocol Parsing
Supavisor doesn’t just blindly forward bytes. It parses the PostgreSQL wire protocol (startup messages, authentication, simple query, extended query) at the byte level. It intercepts commands that alter session state to ensure transactions are isolated, while allowing stateless commands to pass through efficiently.
The Secret Sauce: The Erlang VM (BEAM)
To understand how Supavisor handles spikes, you have to understand the environment it runs in. Supabase chose Elixir/Erlang specifically because BEAM was designed by Ericsson in the 1980s for telecom switches — systems that must handle millions of concurrent phone calls and never go down.
Here is how BEAM’s internals translate to Supavisor’s superpowers:
A. The Actor Model and Lightweight Processes
In BEAM, processes are not OS threads. They are extremely lightweight green threads managed by the VM.
- Creating a process takes microseconds and a few kilobytes of memory.
- When a client connects to Supavisor, BEAM spawns a dedicated process just for that client.
- If a traffic spike brings 50,000 new connections, BEAM simply spawns 50,000 processes. The BEAM scheduler handles distributing these processes across the available CPU cores seamlessly.
B. Preemptive Scheduling
In languages with a single-threaded event loop (like Node.js or Python), a single long-running operation can block the entire system.
In BEAM, schedulers are preemptive. Every process gets a reduction count (essentially a time slice). Once a process uses up its reductions, the scheduler pauses it and moves to the next one. This ensures that a massive spike in traffic on Tenant A does not starve Tenant B of CPU time. Fairness is built into the VM.
C. “Let it Crash” and Supervision Trees
Erlang’s philosophy is that errors should crash the isolated process, not the whole system. Supavisor uses OTP (Open Telecom Platform) Supervision Trees.
- If a single client connection process crashes due to a malformed packet, the Supervisor simply restarts that specific process.
- If a backend Postgres connection dies, the supervisor removes it from the pool and spins up a fresh one.
- The rest of Supavisor (and the other 100,000 active connections) are completely unaffected.
Anatomy of a Traffic Spike
Let’s look at exactly what happens inside Supavisor when a sudden spike of 10,000 concurrent requests hits.
1. Wire-Speed Acceptance (Acceptor Pool)
Supavisor runs a pool of acceptor processes. These processes do nothing but accept TCP connections from the OS kernel’s backlog as fast as possible and immediately hand them off to a dedicated client process. This means Supavisor can ingest connections at wire speed, preventing the OS network stack from dropping packets during a surge.
2. Zero-Contention State Lookups (ETS)
To route connections, Supavisor needs to know pool sizes, database URLs, and credentials. If this were stored in a traditional database, a traffic spike would bottleneck on state lookups. Instead, Supavisor loads tenant configurations into ETS (Erlang Term Storage). ETS is an in-memory, highly concurrent key-value store native to BEAM. It allows thousands of processes to read tenant routing data simultaneously with nanosecond latency and zero contention.
3. Backpressure via Queueing
Suppose you have a Postgres database that can safely handle 100 concurrent connections, but the spike sends 10,000 concurrent queries to Supavisor.
- Supavisor checks out the 100 available backend connections.
- For the remaining 9,900 queries, Supavisor places the client processes into an Erlang queue.
- Because Erlang processes are cheap, holding 9,900 processes in memory waiting for a backend connection consumes very little RAM (roughly 50–100MB total).
- As Postgres finishes transactions and returns connections to the pool, Supavisor pops queries off the queue and executes them.
4. Protecting Postgres
The primary job of Supavisor during a spike is to act as a shock absorber.
Without Supavisor, a 10,000-connection spike would cause Postgres to attempt to spawn 10,000 backend processes. Postgres would run out of memory, thrash the CPU, and crash.
With Supavisor, Postgres only ever sees a maximum of 100 steady connections. The latency for the end-user might increase slightly (their query sits in the queue for a few extra milliseconds), but the database stays alive and responsive.
5. Graceful Degradation
What if the queues get too long? Supavisor can be configured to reject new connections or return specific error messages rather than allowing memory to exhaust. Because of the Actor model, dropping a connection is as simple as terminating that specific process — the OS reclaims the socket immediately, and the system degrades gracefully without panicking.
TL;DR: The Lifecycle of a Spiked Request
To summarize, here is the exact flow when a spike hits Supavisor:
- Spike hits: 10,000 clients try to connect simultaneously.
- TCP Handshake: BEAM acceptors accept the sockets instantly.
- Process Spawning: 10,000 lightweight BEAM processes are spawned.
- Auth/Routing: Processes look up tenant credentials in ETS (nanosecond reads).
- Pool Checkout: Processes attempt to check out a Postgres connection.
- The Queue: Only 50 Postgres connections exist. 50 processes get them; 9,950 processes are parked in memory, waiting.
- Execution: Postgres executes a query in 5ms. Supavisor returns the result, gives the connection back to the pool, and wakes up the next process in the queue.
- Drain: The spike subsides, and the queue drains smoothly without Postgres ever breaking a sweat.
Conclusion
By leveraging Elixir and the Erlang VM, Supavisor achieves massive concurrency, fault tolerance, and low-latency routing that would be incredibly difficult to replicate in traditional thread-based or callback-based languages.
It acts as the ultimate bouncer for your database. During a traffic spike, it politely asks the surge of queries to wait in line, ensures the database is never overwhelmed, and processes the queue as fast as Postgres can handle it.
For Supabase, this means they can offer a truly serverless, scalable Postgres experience without worrying that a single viral moment will take down their infrastructure. And because it’s open source, you can deploy Supavisor in your own infrastructure to bring that same BEAM-powered resilience to your databases.
(If you’re interested in the nitty-gritty code, check out the Supavisor GitHub Repository.)
메타데이터
- post_id
- d184d41c6ee6
- slug
- how-supabase-built-a-postgres-pooler-to-survive-massive-traffic-spikes-d184d41c6ee6
- url
- https://medium.com/@lakin-mohapatra/how-supabase-built-a-postgres-pooler-to-survive-massive-traffic-spikes-d184d41c6ee6
- canonical_url
- https://medium.com/@lakin-mohapatra/how-supabase-built-a-postgres-pooler-to-survive-massive-traffic-spikes-d184d41c6ee6
- author_url
- https://medium.com/@lakin-mohapatra
- status
- ok
- fetched_at
- 2026-07-09 05:26:43