Scaling Postgres for Cartnest
Cartnest started as a straightforward FastAPI backend with a single Postgres instance. It worked — until it didn't. As I modelled real trading traffic, reads on the product catalog and transaction history became the bottleneck long before writes did.
Reads and writes want different things
The first realization was that a single node forces reads and writes to compete for the same resources. Splitting them apart — a primary for writes, replicas for reads — let each scale on its own terms.
app -> primary (writes)
-> replica 1 (reads)
-> replica 2 (reads)Fragmenting the heavy tables
Replicas help reads, but they don't shrink a hot table. For the transactions table I introduced fragmentation so that no single partition carried the whole load.
- Partition by time so recent data stays hot and small
- Keep foreign keys local to a fragment where possible
- Measure before and after — never assume the split helped
Distributed systems don't make problems disappear. They move them somewhere you can reason about.
What I'd do differently
I'd reach for observability first. Half of the wins came from finally seeing which queries were slow, not from the architecture itself.