Choosing Infrastructure.
Every infrastructure decision is a bet. Here's what I chose to run Circus on — and why microservices, PostgreSQL, and cloud-agnostic design beat the alternatives.
I’ve tested nearly every major cloud provider and infrastructure setup. Here’s what actually runs Circus and why.
The hardest infrastructure question for an early-stage platform isn’t “how do we scale?” — it’s “how do I build something that scales later without having to throw it away?” The answer is boring and it works: stateless services, clean boundaries, and a database that every cloud knows how to run.
The foundation: microservices
Circus runs on a set of independent Bun HTTP services. Each service has one job, owns its own data, and exposes a well-defined API. No shared tables. No cross-service database joins. When one service needs data from another, it calls that service’s API or consumes events from Apache Kafka.
Kafka handles communication where eventual consistency is fine — content events, membership changes, analytics. Direct HTTP handles anything that needs a synchronous response. Kafka producers are fire-and-forget: publish and move on.
The payoff is that each service scales independently. A sudden spike in feed reads doesn’t touch the auth service. A write-heavy upload burst doesn’t touch the community service. Nothing requires coordinated scaling.
Horizontal scaling
Every service is stateless. Scaling means running more instances behind a load balancer — nothing inside the service changes. No sticky sessions. No shared in-process state. Deployments and restarts are zero-ceremony.
Each service scales independently — spin up more instances of whichever service is under load, without touching the others.
PostgreSQL at the center
PostgreSQL runs behind a connection pooler. For a social platform at this stage, Postgres is fast enough, operationally familiar, and has well-understood scaling paths — every major cloud platform runs it well.
The architecture is designed to add read replicas and a caching layer when traffic makes them necessary. I know exactly where each goes and what the implementation looks like. The rule is simple: add them when the numbers say to, not before.
Hyperscalers and service providers
I’ve built to run across any major cloud — not locked to one provider. In development I’ve tested nearly every major hyperscaler and managed service provider. The stack — stateless Bun services, Postgres, Kafka — runs cleanly on all of them.
No proprietary managed services. No cloud-specific SDKs in application code. The services don’t know or care which provider they’re running on.
The cost reality
Cloud cost is real, and the gap between providers is larger than most comparisons let on. Here’s an illustrative monthly estimate for a small-to-medium production workload — 3 services, Postgres, Kafka, basic load balancing:
Illustrative monthly estimate — 3 services, Postgres, Kafka, load balancing. Estimates vary by workload.
Vercel’s convenience premium is real. Netcup and Hetzner’s operational overhead is real too — you’re managing more yourself. I’ve tested infrastructure across most of the major providers. The stack — Bun services, PostgreSQL, Kafka — runs cleanly on all of them. The decision of where to run is about cost tolerance and ops capacity, not capability.