DEV Community

Cover image for Why Supavisor 1.0 Is Written in Elixir (And Why That's Actually a Brilliant Move)
ARAFAT AMAN ALIM
ARAFAT AMAN ALIM Subscriber

Posted on

Why Supavisor 1.0 Is Written in Elixir (And Why That's Actually a Brilliant Move)

A behind-the-scenes look from the creator of Elixir himself.


"Wait... Elixir? Really?"

Picture this. You're scrolling through Hacker News, sipping your third coffee of the morning, and you see the headline: "Supabase launches Supavisor 1.0 — a Postgres connection pooler."

Cool. Solid. Useful.

Then you click in, read the docs, and realize... it's written in Elixir.

And somewhere in the comments, you can almost hear the collective developer eyebrow-raise:

"Why on earth would they build a Postgres connection pooler in Elixir?"

It's a fair question. Most people in the broader programming community don't reach for Elixir when they think "infrastructure tool." They think Go. They think Rust. They think "something with a fancy concurrency model and a logo that screams performance."

So when José Valim — yes, the creator of Elixir himself — went on record to explain why this choice actually makes a lot of sense, it was worth listening to. He even admits upfront that he's biased (which, fair, he literally invented the language). But his answer is surprisingly not about Elixir.

It's about something deeper. Something older. Something built decades ago to keep your phone calls from dropping.

Let's dig in.


First, Let's Get the Credits Out of the Way

Before going down the rabbit hole, José gave a quick shoutout: huge congrats to the Supabase team on shipping Supavisor 1.0. He also mentioned that he and his colleagues at Dashbit got to contribute to this milestone in small ways. So this isn't some random outsider commentary — this is someone who's had hands on the actual code, and who happens to also be the creator of the language it was written in.

Pretty cool position to write about something from, honestly.


Okay, So What Is a Connection Pooler Anyway?

Before we can answer the "why Elixir" question, we need to make sure we're all on the same page about what Supavisor actually does. Because if you've never wrestled with database connections at scale, the whole concept might feel a bit abstract.

So let's set the scene.

The Cloud Functions Nightmare

Imagine you're running cloud functions. Lambda. Vercel functions. Cloudflare Workers. Whatever the flavor of the day is. These little serverless guys spin up, do their job, and disappear into the void.

Now imagine each of those functions needs to talk to your Postgres database.

Sounds simple, right? Just connect, run the query, return the data, disconnect. Easy.

Except... opening a Postgres connection is not free.

Every time you connect to Postgres, there's an entire handshake ritual. TCP setup. Authentication. SSL negotiation if you're being responsible. Session initialization. The works. It's like every time you wanted to chat with your friend, you had to first knock on their door, introduce yourself, show ID, fill out a visitor form, and wait for them to brew you tea before you could even ask what's up.

Now multiply that by thousands of cloud function invocations per second.

You see the problem.

The Node.js / Ruby Special

It gets worse. José pointed out something interesting about languages like Node.js and Ruby — they can't efficiently leverage all your CPU cores out of the box (single-threaded event loops, GVL, that whole drama). So what do you usually do? You spin up multiple instances of your app.

And what does each instance want? Yep — its own connection (or pool of connections) to Postgres.

So now you've got:

  • A bunch of app instances...
  • Each holding open multiple Postgres connections...
  • Or worse, re-opening them on every request...
  • And Postgres on the other end going, "Please. I'm tired."

Postgres connections are expensive in terms of memory too. Each one chews up RAM on the database server. Get enough of them and you'll watch your database performance fall off a cliff in real time.

Enter the Connection Pooler

This is where a connection pooler comes in like the bouncer at an exclusive club.

Instead of every app instance and every cloud function knocking on Postgres's door, you put a proxy in front of Postgres. This proxy keeps a fixed set of connections to Postgres open and ready to go. When your app needs to talk to the database, it talks to the pooler instead. The pooler basically says:

"Hey, no need to do the whole handshake thing. I've already got a warm connection ready for you. Use this one."

Your app gets fast database access. Postgres doesn't get overwhelmed. Everybody's happy.

That's what Supavisor is. A connection pooler — but a particularly fancy one, designed from the ground up to be:

  • ☁️ Cloud native
  • 🏢 Multi-tenant — meaning you can connect to a bunch of different Postgres databases at the same time

That last part is huge for a company like Supabase, who hosts who-knows-how-many Postgres databases for their customers. They need one pooler that can juggle them all.


Now for the Real Question: Why Elixir?

Okay, so we understand what Supavisor does. It manages a lot of connections, across a lot of databases, for a lot of clients. And it has to do this without falling over.

So why pick Elixir for this job?

Here's the twist José drops:

"It's not because of Elixir. It's because of the Erlang virtual machine that Elixir runs on."

Plot twist. The hero of this story isn't actually Elixir. Elixir is more like... the cool modern frontend for an absolute powerhouse of a backend. That backend is the BEAM — Erlang's virtual machine.

To understand why the BEAM is unreasonably good for this kind of work, we need to take a quick history detour. Don't worry, it's a fun one.


A Quick Trip Back to the Telephone Era

Erlang wasn't created in a Silicon Valley garage by a hoodie-wearing twenty-something. It was created in the 1980s by Ericsson — a Swedish telecommunications company. And they had a very specific problem to solve.

They needed to build software for telephone switches.

Now think about what a telephone switch actually does. It sits there and:

  • Accepts connections from a bunch of different places
  • Routes those connections to other places — services, houses, phones
  • Keeps thousands (or millions) of these connections alive at the same time
  • Cannot, under any circumstances, drop your call because something on the other end of the network had a hiccup

Sound familiar?

Because that's exactly what a connection pooler does. Just swap "phone calls" for "database connections." The shape of the problem is identical:

  • Accept connections coming in from your services, your cloud functions, your request handlers
  • Keep open connections to Postgres (the "destination" on the other side)
  • Route incoming traffic to the right outgoing connection
  • Handle a staggering number of these simultaneously
  • Don't fall over when something somewhere goes wrong

Erlang was built for this. Literally. It is the language equivalent of a tool forged for one specific job, and that job happens to be the same job a connection pooler does.

When José said the BEAM has "all the principles and foundations" needed for Supavisor, he wasn't being generous — he was just being accurate.


Scale to Millions (No, Really)

Here's where it gets really wild.

You want your connection pooler to scale. Not "scale" as in "handle a few hundred connections." Scale as in millions of concurrent connections. That's the kind of territory Supabase plays in.

Most languages start sweating at, like, 10,000 concurrent connections. The BEAM? It just kind of shrugs. Handling massive numbers of lightweight processes is literally what it was designed to do — because back in the telephone days, every call was a process, and a busy switch had millions of them.

So when Supavisor needs to scale up to handle Supabase-level traffic, it's not fighting against the runtime. The runtime is already wired for this.


But What Happens When One Pooler Isn't Enough?

Here's a great point José made that often gets overlooked.

Imagine Supavisor is humming along, and traffic keeps growing. Eventually, one instance of the pooler isn't enough. You need to spin up multiple Supavisor nodes, all working together to handle the load.

Now you've got an interesting situation. Let's say:

  • Service A is connected to Pooler Node 1
  • That request needs to talk to a specific Postgres database
  • But the warm connection to that database is actually living on Pooler Node 2

What do you do?

Option 1: Both nodes maintain connections to every database. Simple, but wasteful and doesn't scale well.

Option 2: Route the request from Node 1 over to Node 2, where the right connection already exists.

Option 2 is often the smarter play. And here's the magic: Erlang gives you this kind of inter-node communication essentially out of the box. Building distributed systems where nodes can talk to each other, hand off work, and behave as a single coordinated cluster is one of those things the BEAM has had baked in for decades. In most other ecosystems, you'd be reaching for Redis pub/sub, or gRPC, or some custom messaging layer. In Elixir/Erlang, it's just... there.

That's not a small thing. That's a massive head start.


Fault Tolerance: The Quiet Superpower

Here's the part that should make any infrastructure engineer's eyes light up.

When you're running a connection pooler, things will go wrong. A connection will die. Postgres will hiccup. A client will misbehave. Some bug will show up in production at 3 AM (because of course it will).

The question is: when one of those things goes wrong, what happens to everything else?

In a lot of systems, one bad connection or one crashed handler can take down a whole process — or worse, the whole service. You suddenly lose every other connection that was happily doing its job, just because one neighbor misbehaved.

Erlang's answer to this is the "let it crash" philosophy combined with deep, structural isolation between processes. Each connection lives in its own lightweight process. If it crashes, only that process dies. The supervisor restarts it. Nothing else even notices.

It's like if your apartment building was designed so that if one apartment caught fire, the fire just... politely stayed in that one apartment. The rest of the building doesn't care. Life goes on.

For a connection pooler with thousands or millions of connections, this isolation isn't a "nice to have." It's table stakes. You absolutely cannot have one weird query bringing down connections for unrelated tenants on a multi-tenant system.

Erlang handed Supavisor this guarantee on a silver platter.


The Big Takeaway

So let's zoom back out and put it all together.

Supavisor is a connection pooler that needs to:

  • Handle massive numbers of concurrent connections ✅ (BEAM was built for this)
  • Be multi-tenant, juggling many databases at once ✅ (lightweight processes make this trivial)
  • Scale across multiple nodes with smart request routing ✅ (Erlang has distribution baked in)
  • Be fault tolerant, with crashes contained to single connections ✅ (isolation is the BEAM's middle name)
  • Be cloud native and ready for production at serious scale ✅ (this is the BEAM's home turf)

Every. Single. Requirement. Lines up with what Erlang was originally designed to do for telephone switches forty years ago.

Choosing Elixir for Supavisor isn't a quirky language preference. It's not "we like Elixir, so we'll force-fit it here." It's actually one of those rare moments where the problem and the tool are so well-matched that picking anything else would feel like trying to dig a swimming pool with a teaspoon.


Should You Use Supavisor?

Here's the practical TL;DR José landed on:

If you're running Postgres in production, and either:

  • You're spinning up new database connections dynamically all the time (hi there, serverless folks 👋), or
  • You've got too many services keeping too many connections open to Postgres, and you're starting to feel that memory pressure...

...then yeah, you should absolutely give Supavisor a try. Sticking a smart pooler in front of Postgres can dramatically reduce your connection overhead and let your database actually breathe.

And as a little bonus suggestion from José himself: if all this talk about lightweight processes, fault tolerance, distributed systems, and "let it crash" got your inner curiosity tingling — go check out Elixir. You don't need to be building telephone switches or connection poolers to benefit from those foundations. Plenty of web apps, real-time systems, and backend services would be very happy to live on the BEAM too.


Final Thought

There's a lesson hiding inside this whole story, and it's not really about Elixir or Erlang specifically.

It's that sometimes, the best engineering decisions come from recognizing that someone, somewhere, has already solved the shape of your problem — even if they solved it for a completely different domain. The Ericsson engineers in the 1980s were not thinking about cloud functions or Postgres. They were thinking about phone calls. But the structure of their problem — many concurrent connections, fault tolerance, distributed routing — turned out to be the structure of an enormous number of modern infrastructure problems too.

Supavisor 1.0 is a great example of that lesson playing out in 2026. Decades-old runtime, brand-new product, and a very nice fit between the two.

Congrats again to the Supabase team. And if you're a backend dev who's never given Elixir a serious look — maybe today's the day. ☕


Have you tried Supavisor yet? Or have your own war stories about Postgres connection management at scale? Drop them in the comments — I'd love to hear how you're handling it.

Top comments (0)