Development

Monolith or Services for a Small Team

Every few months a small team decides the answer to its problems is to split the application into services. Sometimes it is. More often it trades a code-organisation problem, which is cheap to...

A single large block and a cluster of small blocks on a balance scale

Every few months a small team decides the answer to its problems is to split the application into services. Sometimes it is. More often it trades a code-organisation problem, which is cheap to fix, for an operations problem, which is not.

What services actually cost

The moment you have more than one deployable, you have taken on network calls between things that used to be function calls, which means timeouts, retries and partial failure. You have distributed data, so a change that spans two services is now a coordination problem. You have more to deploy, more to monitor, and more places for a request to get lost. A team of four feels all of this and gains little, because the thing services buy you is independent scaling and independent teams, and you have neither.

What people are really complaining about

Usually it is that the codebase is a tangle: business logic spread through the UI, modules that reach into each other’s internals, no clear line between the billing code and the reporting code. That is a real problem, and splitting into services does not fix it. You just get the same tangle spread across a network.

The fix is boundaries inside the single application. Pick the seams that match how you talk about the product: accounts, billing, notifications. Give each one a defined interface and a rule that other modules go through that interface, not around it. Now you have a modular monolith: one thing to deploy, but with the internal clarity that made people want services.

The signs it is genuinely time to split

Look for a real forcing function. One part of the system needs to scale on completely different hardware or schedule than the rest. One part changes so often that its releases are held back by the rest of the app. A separate team is forming and needs to own something end to end without coordinating every deploy. When one of those is true, split that one piece and leave the rest alone.

If you do split

Do it along a boundary you have already proven inside the monolith. Extracting a module that already has a clean interface is a weekend. Extracting one that does not is a quarter. Move one service out, live with it for a while, and only continue if the benefit was real.

The default

For most small teams, most of the time: one deployable, strict internal modules, and the discipline to keep the boundaries clean. It is less exciting and it ships more.

Common questions

Is a monolith bad?

No. A well-structured single deployable is the right default for most small teams. The problems people blame on the monolith are usually just poor internal boundaries.

When should we split?

When a part of the system has a genuinely different scaling need, a different release cadence, or a different team owning it. Not before.

What is a modular monolith?

One deployable with strict internal module boundaries: modules talk through defined interfaces, not by reaching into each other. It gives you most of the clarity of services without the operational cost.

Get new posts by email

Occasional notes on front-end and shipping software. No spam.

Have a project in mind?

Tell us what you are building. We will come back within 48 hours with a plan and a cost estimate, free.