When to split a monolith is a question of team scaling, not just tech. Learn how to weigh the operational overhead against the benefits of decoupling.

We’ve all been there: staring at a single repository that takes 15 minutes to build and runs a test suite that feels like a marathon. The temptation to reach for microservices is immense, but I’ve learned the hard way that splitting a monolith is often a path to distributed system hell rather than a productivity boost.
If your team is struggling with a monolithic codebase, you shouldn't jump straight to microservices. Instead, you need to determine if your pain is caused by the architecture or by your internal boundaries.
Most engineers treat "when to split a monolith" as a technical challenge. It isn't. It’s an organizational one. You should only consider moving to a distributed architecture when the cost of coordination exceeds the cost of operational complexity.
Here are the signals that it’s actually time to break things apart:
If you aren't hitting these walls, you’re likely better off keeping the monolith. It’s easier to maintain, debug, and refactor. Before you start carving out services, make sure you aren't just trying to solve a lack of discipline with a new infrastructure layer.
I once worked on a team that decided to split a service based on "clean architecture" principles. We ended up with three services that required a single database transaction to function correctly. We spent about two weeks just managing the distributed tracing and eventual consistency issues that arose from that split.
We were chasing a fantasy of independence, but we had created a tightly coupled distributed system. We had all the downsides of a monolith—shared database locks—with the added bonus of network latency and service discovery failures.
If you find yourself needing to share data across services, you’re often better off sticking to a modular monolith approach. Use clear internal boundaries, distinct packages, and strict API contracts, just like you would with designing error responses clients can actually use for your API.

Sometimes, the "monolith" isn't the problem. The problem is lack of modularity. If your code is a "big ball of mud," splitting it into smaller, equally messy services won't help.
I’ve seen teams migrate to microservices only to realize they still have to deploy five services in a specific order to get a single user story out the door. That’s not agility; that’s a distributed monolith.
Before you split:
If you're dealing with performance issues, consider if you're just hitting database constraints. Sometimes, when to denormalize your database for production performance is a more effective lever than changing your entire service topology.
Q: How do I know if my monolith is too big? If your CI pipeline takes more than 10-15 minutes, or if two teams are constantly stepping on each other's toes in the same files, that's a sign. Start by splitting the build or moving to a monorepo structure with strict ownership boundaries before ripping out the runtime.
Q: What’s the biggest risk of splitting? Operational complexity is the silent killer. You’ll need better monitoring, robust observability, and a plan for when Service A is up but Service B is flapping. If your team isn't ready to manage distributed state, stay where you are.
Q: Is a modular monolith a valid long-term architecture? Absolutely. Many high-scale companies keep their code in a monolith for years, using language-level boundaries to keep teams separated. It’s often the most pragmatic choice.

I’m still not convinced that microservices are the default for most mid-sized teams. We’ve become obsessed with the "Netflix architecture" without having the Netflix-sized engineering team to support it.
Next time I'm faced with this decision, I’ll be much more aggressive about enforcing boundaries within the monolith first. If I can't build a clean interface between two modules in the same memory space, I have no business trying to build a clean interface over a network. The network won't make your code better; it will just make your mistakes harder to debug.
Pagination that scales past page 1000 requires moving away from traditional offset-based methods. Learn how to implement cursor-based keyset pagination.