Horizontal Scaling a Monolith Before Reaching for Microservices

A client came to us convinced their growth problem required a microservices rewrite — the monolith was struggling under load and every article they'd read pointed to service decomposition as the fix. Before agreeing to a rewrite, we profiled the actual bottleneck and found it wasn't architectural at all: a handful of unindexed queries and a single-instance PHP-FPM pool with a low worker count were the real limits. We fixed those first.
Running multiple stateless application instances behind a load balancer, with sessions moved out of local file storage into Redis, got us most of the way to horizontal scalability without touching the codebase's structure. The monolith didn't need to become services to run on more than one box — it needed to stop assuming it was the only box, which mostly meant auditing for local file writes and in-memory state that wouldn't survive a second instance.
The database, not the application tier, became the actual constraint once we could scale application instances freely. We added a read replica for reporting queries and non-critical reads, moved the heaviest background jobs to dedicated worker instances separate from the web-serving instances, and that combination handled roughly 10x the original request volume without a single service boundary being drawn.
We did eventually extract one piece — an image processing pipeline — into its own service, but only once it had a genuinely different scaling profile (CPU-bound, bursty) from the rest of the request-serving code, and only after the monolith itself was no longer the bottleneck. Extracting it earlier would have added network calls and deployment complexity for a problem the monolith wasn't actually causing yet.
The lesson we keep relearning on client projects: microservices solve organizational and scaling-profile problems, not slow-query problems. A team of six engineers maintaining a dozen services pays a real coordination and operational tax, and that tax is only worth it once a monolith's genuine architectural limits — not its unoptimized queries — are what's holding growth back.


