Skip to main content

Architecture

Split the system, or keep it whole

One vendor says microservices are how you scale, the other says they will sink you — both are describing a real project, just not necessarily yours.

Ask us which one fits

Why this choice is so noisy

The confusion comes from advice written by companies that split a system after it was already large, being read by teams who have not shipped the first version yet. Every famous migration starts from a working monolith carrying real traffic. Nobody writes the post-mortem about the service estate that never launched.

The question that settles it most often is short: how many separate teams need to deploy on their own schedule? If the answer is one, you are choosing between a monolith and a distributed monolith, which is the same code with network calls in the middle and a considerably worse debugging story.

Where they diverge

The places the choice actually bites

Not a feature list. These are the six points where the architecture decides what your team's week looks like.

  • Changing something in two places

    In a monolith, renaming a field is one commit and one deploy. Across services it is a versioned API change, two deploys and a compatibility window.

  • Transactions and joins

    A monolith gets Postgres transactions and foreign keys for free. Split orders from payments and you are writing saga logic and nightly reconciliation jobs instead.

  • What happens at 3am

    One process failing is one log to read. Ten services need distributed tracing, with OpenTelemetry and correlation IDs on every hop, before an outage is even legible.

  • Deploy independence

    The real prize of services: the payments team ships on Tuesday without waiting for the search team's release. That prize is worth nothing with one team.

  • Running it locally

    A monolith starts with one command against one database. A service estate needs the whole set running, or mocks that drift from what production actually returns.

  • Scaling the expensive part

    If PDF generation eats your CPU, a monolith scales the entire application to cope. A separate service scales only that, on its own machine size.

The trade-offs

Four dimensions that decide it

The same four questions come up in every scoping call we have about this, usually in this order.

COST OF CHANGE
Monolith, until you have several teams
One repository, one deploy, and a compiler that finds every call site when you rename something. Services make each change cheaper to reason about locally and dearer to coordinate across a boundary.
TIME TO LAUNCH
Monolith, and not close
An MVP that ships in 12–16 weeks as one platform picks up weeks of setup as services: a broker, service discovery and per-service pipelines, all before a customer sees a screen.
WHO MAINTAINS IT
A generalist team, or a platform owner
A monolith can be handed to two competent full-stack developers. A service estate quietly assumes somebody owns the cluster, the broker and the CI pipeline, and that role has to be filled or bought in.
WHAT BREAKS FIRST
Build times, versus the network
Monoliths grow slow to test and frightening to deploy. Service estates fail at the edges instead: retries, timeouts, a queue backing up, one service still reading the old schema.

Which one fits you

Read both columns honestly. If you land in the left one, that is the cheaper build and the faster launch, and it is the right answer far more often than this industry likes to admit.

Choose a monolith if…

  • One team owns the codebase and ships on a shared release.
  • You are still finding out which features customers actually use.
  • Your core data is heavily joined: orders, users and billing all reference each other.
  • Nobody on your team wants to be responsible for Kubernetes.

Choose microservices if…

  • Several teams need to deploy on their own schedule, without a release meeting.
  • One workload has a wildly different load or hardware profile, like video or ML inference.
  • A regulated component must be isolated with its own data and audit boundary.
  • You already run the platform for something else: CI, tracing and on-call rotas.
FAQ

Frequently Asked
Questions

Common questions about splitting a system into services, and when not to.

Not if it has internal boundaries. A modular monolith keeps clear module edges, with separate domains and no module reaching into another module's tables, while still deploying as one unit. When a module genuinely needs to leave, the seam is already drawn and the extraction is contained work rather than a rewrite. The debt comes from a monolith with no boundaries at all, where every part reads every table. That is a discipline problem, and splitting into services does not fix it. It moves it onto the network, where it is harder to see.

The trigger is organisational before it is technical. Watch the release meeting: when shipping means coordinating three teams' changes into one deploy window, and one team's feature is regularly held back by another team's bug, the shared deployable has become the bottleneck. The second trigger is a workload with a genuinely different shape, like video transcoding or model inference that wants different hardware. Slow response times on their own are not a trigger. That is usually a missing index or an N+1 query, and splitting the code will make it worse.

They are describing scaling teams, not scaling traffic, and the pitch tends to blur the two. A single well-built application on a decent database handles far more load than most products ever see, and you scale it by running more copies behind a load balancer. What services buy you is scaling one part independently, which matters when one workload is genuinely expensive. Ask which specific component they expect to outgrow the rest, and at what traffic. If there is no answer, the recommendation is a default rather than a diagnosis.

Mostly time in places that produce nothing a customer can see. You need service-to-service auth, a broker or an API gateway, tracing so a single error is followable across hops, a pipeline per service, and a plan for the window where one service reads the new schema and another still reads the old one. Expect that groundwork to add weeks before the first feature lands, then to keep taking a share of every sprint. It earns its keep when it removes a real coordination cost, and it is dead weight when it does not.

Yes, and it is the path we recommend most often. We build the first version as a modular monolith with the domain boundaries drawn deliberately, so orders, billing and identity do not share tables even though they share a process. When one of them needs to move out, it leaves behind an interface that already exists. Going the other way, folding a service estate back into one deployable, is also something we do, but it is harder because you inherit whatever data drift built up while the databases were separate.

Have a project in mind?

Fixed price after a paid discovery — no hourly billing. A real engineer reads every enquiry, and we reply within 24 hours.