infrastructureself-hosting7 min read

Owning the Stack: Moving Our Sites and Data Onto Brumalia Infra

8 June 2026

Most small product teams inherit the same stack by default.

Frontend on Vercel. Database on Supabase. Move quickly, avoid infra, and let the platform smooth out the rough edges.

There is a reason that stack became popular. It works. It is fast to ship with, pleasant to use, and hard to argue with when the main goal is getting something live without burning weeks on setup.

We used that pattern too.

But over time, we found ourselves asking a more useful question than "what is the modern default?"

We started asking: what actually fits the products we are building?

That question matters because convenience is not the same thing as fit. A platform can be good and still be wrong for your operating model.

At Brumalia, that is what changed. We have started moving parts of our stack off Vercel and Supabase and onto infrastructure we run ourselves. That includes websites, routing, and the database layer behind smaller apps and internal tools.

This was not an anti-cloud rant or a performative self-hosting phase. It was a practical decision about control, cost, clarity, and architecture.

The default startup stack is good, until it isn't

Vercel and Supabase solve real problems.

Vercel gives you a polished deployment workflow, preview environments, and a frontend hosting model that feels almost frictionless. Supabase gives you Postgres plus auth, storage, realtime features, and a developer experience that is far better than wiring all of that yourself from scratch.

If you are early, that is a strong offer.

But the appeal of a managed stack starts to weaken when your apps are small, your traffic is predictable, and your team is technical enough to run a clean VPS setup without drama.

At that point, you are not just paying for hosting or database capacity. You are paying for abstraction. Sometimes that is worth it. Sometimes it is just overhead wearing a nice UI.

That was the point we reached.

Why we moved

We wanted a stack that matched the way we actually work.

For a lot of smaller Brumalia apps, we do not need a broad managed platform with layers of bundled product features. We need:

  • an application container
  • a private Postgres instance
  • a reverse proxy handling TLS and routing
  • clean domain control
  • backups and a restore path
  • an architecture we can explain in one minute

That is a much simpler problem than the full "modern platform" story tends to imply.

We also wanted fewer dependencies sitting between us and our own products. When a site is live, we want to know exactly where traffic lands. When a domain changes, we want to know which layer owns the cutover. When a database exists, we want to know whether we truly need a managed platform or just a good Postgres setup.

That kind of clarity gets more valuable as you build more than one thing.

Why we did not self-host Supabase by default

This is the part people often blur.

Supabase is not just "Postgres, but self-hosted." It is a wider platform. That can be useful, but it also means extra services, extra operational surface area, and extra complexity.

If you specifically need the Supabase stack, that is fine. Use it for a reason.

But for many smaller apps, the honest requirement is just relational data plus app-layer logic. In those cases, plain Postgres is usually the better starting point.

That gives us:

  • less infrastructure to maintain
  • fewer services that can fail
  • lower resource overhead
  • simpler mental models
  • a cleaner path to private-by-default database access

So our default is no longer "Supabase unless proven otherwise."

It is closer to this:

Use plain Postgres first. Add platform layers only when the app genuinely needs them.

That sounds obvious, but plenty of teams do the reverse. They start with the heavier platform shape, then spend months carrying features they never truly needed.

Moving the websites

The website side of the move was less about code and more about ownership.

We wanted our domains routing through infrastructure we control, with a shared edge we understand, rather than having project state spread across external platforms as the hidden source of truth.

In practice, that means:

  • domains point to our VPS
  • a shared Caddy edge handles public traffic and TLS
  • app containers sit behind that edge
  • www and apex routing are explicit
  • websites resolve because our own infrastructure is answering them

That last part matters.

One of the easiest mistakes in a migration like this is thinking a site is "off Vercel" because the Vercel project was removed. That is not the cutover. The real cutover happens when DNS moves and traffic no longer resolves through the old platform.

Until that happens, the platform is still in the path, whether the dashboard says so or not.

We wanted to get rid of that ambiguity.

What changed operationally

The big shift was not visual. It was operational.

Our stack now makes sharper distinctions between:

  • public edge and private app services
  • website hosting and database hosting
  • DNS control and app deployment
  • lightweight data needs and full platform needs

That gives us cleaner defaults.

For a small app, the pattern is simple:

  • app on the VPS
  • Postgres on the VPS
  • database private on the Docker network
  • reverse proxy at the edge
  • domain routed deliberately

That setup is not exotic. That is the point. It is boring in the right way.

Boring systems are easier to debug, cheaper to run, and less likely to confuse you six months later.

What we gained

The obvious gain is more control.

The more important gains are these:

Clearer architecture

We know where the edge is, where the app is, where the database is, and which layer owns what.

Lower platform dependency

We are less exposed to the habits and pricing models of tools that made sense earlier but fit less well now.

Cleaner cost shape

Instead of distributing small apps across multiple paid platform layers, we can run leaner and make deliberate exceptions when they are justified.

Better operational discipline

Owning the stack forces better habits around backups, secrets, redeploys, and restore paths. That work is real, but it is useful.

A stronger default for future apps

We do not need to re-litigate the whole stack every time we build something small. We have a sensible starting lane.

What we did not gain

Self-hosting is not magic.

You do not become "serious" just because you moved onto your own VPS. You simply take more responsibility back onto yourself.

That means this only works if you are prepared to own the operational basics:

  • backups
  • restore testing
  • TLS
  • secrets handling
  • restart behaviour
  • deployment clarity
  • database exposure rules

If those are missing, the stack may be cheaper on paper while being worse in practice.

That is why we do not treat self-hosting as a badge of honour. It is just one option. The question is whether it fits.

The rule we use now

We are not against Vercel. We are not against Supabase. Both are good products.

What changed is that we stopped treating them as automatic answers.

Our rule now is simple:

Use the smallest infrastructure shape that genuinely fits the job.

For Brumalia, that increasingly means:

  • websites on our own edge
  • small apps on our own VPS
  • Postgres before heavier platform layers
  • managed services used deliberately, not by habit

That gives us a stack we can actually understand, maintain, and grow. If you want more of the build logs and operating notes behind decisions like this, the rest of the archive lives in Writing.

Not because self-hosting is cooler.

Because it is ours.