Skip to content
← Back to blog
·2 min read·

Why I Reach for a Modular Monolith First

Microservices get chosen before anyone works out who is on call for them. Why I start with a modular monolith, and the cases where I do split.

Why I Reach for a Modular Monolith First

Every project that has ever asked me to "make it microservices" has been a team of fewer than five people. Sometimes a team of one. The architecture was chosen before anyone worked out who would be on call for it.

What the split actually costs

A service boundary is a network call, and a network call is a thing that fails halfway. The moment you split a system you have signed up for retries, timeouts, partial failure, distributed tracing to work out what happened, and a deployment order. None of that is hard on its own. All of it is work you now do forever, on every feature, instead of once.

You also lose the transaction. Two tables in one database update together or not at all. Two services do not, and the patterns that paper over that gap, outbox tables, sagas, compensating actions, are exactly the parts of a codebase people get wrong at two in the morning.

What I build instead

A modular monolith. One deployable, one database, and hard boundaries inside it enforced by folder and namespace rather than by HTTP. Each bounded context owns its entities and exposes an interface; nothing reaches into another context's tables. On a recent marketplace build each milestone was a module, which meant a release plugged into the previous one rather than forcing a refactor of it.

If you keep those boundaries honest, splitting later is mechanical. The interface is already there. You move a folder out, put a network call where the method call was, and deal with the failure modes at that point, when you have a real reason and hopefully more than one person to operate it.

When I do split

Genuinely different scaling shapes, where one part needs ten machines and the rest needs one. Genuinely different lifecycles, where a component ships daily and the rest ships monthly. A hard compliance boundary where data must not sit in the same place. A third-party integration so unreliable that you want it failing in its own process.

Notice that none of those are "it feels cleaner". Cleanliness is what boundaries inside the monolith buy you, and they are free.

The part nobody mentions

Someone has to run it. A small team with five services has five sets of logs, five deploys, five dependency upgrade paths and five things that can be the reason the site is down. I have watched a two-person team spend more of the year on their platform than on their product. The product was fine. The architecture was the problem, and it had been chosen on the first day from a conference talk.

Start with one deployable and clean seams. It is much easier to split a well-bounded monolith than to merge a distributed system back together.

#.NET#architecture#modular monolith#microservices#ASP.NET Core