Monolith vs Microservices: Which Architecture Fits Your Team?

What a monolith and microservices really cost to run, why a modular monolith is the right default for most companies, the signs that you actually need to split, and how to extract a service safely when the time comes.

Published 10 min read
Software engineers drawing system architecture boxes and arrows on a whiteboard

Here is an architecture diagram that turns up more often than it should. Fourteen services, a message broker, a Kubernetes cluster, and a team of four developers. The product has not launched yet. Six months later the team spends more time debugging calls between services than building features. Microservices are a good answer to a specific set of problems, mostly problems of large organisations. If you do not have those problems yet, you pay the costs without getting the benefits.

What Each One Means in Practice

A monolith is one application, deployed as one unit, usually with one database. A Laravel or Django app with modules for orders, inventory, and billing is a monolith. Microservices split those modules into separate applications. Each one has its own codebase, its own deployment, ideally its own database, and they talk over the network through HTTP, gRPC, or a message queue.

The appeal is easy to understand. Teams can deploy independently, a slow part can scale on its own, and a failure in one service does not have to take down everything. All true. The question is what you pay for it.

The Bill Nobody Shows in the Diagram

  • Network failures. A function call inside a monolith does not time out. A call to another service can, so every call needs timeouts, retries, and idempotent handling so a retried payment is not charged twice.
  • Data consistency. An order and its stock deduction used to be one database transaction. Across two services you need patterns such as the outbox or a saga, and you have to accept that data is briefly out of sync.
  • Observability. When a request touches five services, logs alone are not enough. You need distributed tracing with something like OpenTelemetry, central logging, and metrics per service.
  • Operations. Each service needs its own CI/CD pipeline, configuration, secrets, health checks, and on-call ownership. In practice this usually means Kubernetes and someone who knows it well.
  • Local development. Running the whole system on a laptop gets hard. Testing a change end to end often needs a shared staging environment, which becomes a queue.

For a small team, this overhead can eat a third of the engineering time. Even large companies revisit the choice. In 2023 the Amazon Prime Video team wrote about moving one monitoring system from distributed components back into a single process and cutting its infrastructure cost by about 90 percent.

The Modular Monolith as the Default

For most companies we work with, the right starting point is a modular monolith. It is one deployable application, but the code is split into modules with clear boundaries. Orders, payments, and inventory each live in their own folder or package, expose a small public interface, and do not reach into each other's tables. Shopify famously runs one of the largest Rails codebases in the world this way.

You get most of the design benefit of microservices, which is clean boundaries and code that a team can own, without the network in between. And if one module later needs to become a service, the boundary is already there. Extracting a well-separated module takes weeks. Untangling a messy monolith takes months.

AspectModular monolithMicroservices
DeploymentOne pipeline, one releaseOne pipeline per service, independent releases
Data consistencyDatabase transactionsEventual consistency, outbox, sagas
DebuggingOne log stream, one stack traceDistributed tracing across services
InfrastructureA few servers or containersUsually Kubernetes, service discovery, a message broker
ScalingScale the whole app, which is fine for most loadsScale each service on its own
Team fitOne to about five teamsMany teams that need to ship independently
Typical running costLowerOften two to three times higher in infrastructure and ops time

Signs You Actually Need to Split

  • Team size. Once you have several teams, say 30 to 50 engineers or more, and they keep blocking each other on the same release, separate deployments start paying off.
  • Very different scaling needs. Image processing, search indexing, or a notification sender that needs ten times the resources of the rest of the app is a good candidate.
  • Different release cadence. A pricing engine that changes daily next to a billing core that changes quarterly and needs heavy review.
  • Isolation requirements. A component that handles card data or other regulated data, where keeping it separate shrinks the audit scope.
  • A different technology fits better. For example, a Go service for a high-throughput gateway next to a PHP business app.

Note what is missing from that list. Wanting to use modern technology, expecting to be big one day, and a monolith that is messy are all poor reasons. A messy monolith split into services becomes a messy distributed system, which is worse.

How to Extract a Service Safely

The approach that works is the strangler fig pattern, named by Martin Fowler. You do not rewrite the system. You route one piece of functionality at a time to a new service while the old code keeps running, and you remove the old code once the new path has proven itself.

  1. 1Pick one module with a clear boundary and a real reason to move, such as notifications or reporting. Avoid the core order flow as your first attempt.
  2. 2Clean up the boundary inside the monolith first. All access goes through one interface, and no other module reads its tables directly.
  3. 3Build the new service behind that same interface, with tracing, monitoring, and alerts from day one.
  4. 4Send a small share of traffic to the new service, compare results with the old path, then increase step by step.
  5. 5Move the data so the service owns it, and remove the old code and tables once nothing depends on them.

Data Ownership Is the Real Boundary

Each service should own its data. Other services ask through an API or listen to events. They do not query its database. Several services sharing one database with writes from all sides is the worst of both worlds: you have the network overhead of microservices and the coupling of a monolith. If two services always need to change the same tables together, they are probably one service.

Architecture Follows the Org Chart

Conway's law says that systems end up mirroring the communication structure of the organisation that builds them. It cuts both ways. Ten services owned by one team of five means every developer has to hold the whole distributed system in their head. One giant monolith shared by eight teams means constant merge conflicts and release coordination. Draw the team boundaries first, then let the service boundaries follow.

Start with a monolith you can split, and split it when a team, not a diagram, asks for it.

At Salamun Teknologi we design and build backends for growing companies, from modular monoliths in Laravel or Go to services on Kubernetes when the load and the team size call for it. If you are weighing a split or a rewrite, we can review your current system with you before any code changes.

Key takeaways

  • Microservices solve problems of team scale and independent deployment, and they bring network failures, data consistency work, and heavier operations with them.
  • A modular monolith with clear module boundaries is the right default for most companies and makes a later split much cheaper.
  • Split when teams block each other, a part needs very different scaling or release cadence, or regulated data needs isolation.
  • Extract services one at a time with the strangler fig pattern, starting from a module with a clear boundary.
  • Each service must own its data, and service boundaries should follow team boundaries.
Share this article

Related articles

More articles on software development, AI, cloud, and infrastructure.

Smartphone with app wireframes next to a notebook and calculator on a deskSoftware Development

10 min read

How Much Does It Cost to Build a Mobile App in Indonesia?

Indicative price ranges in Rupiah for simple, medium, and complex mobile apps, what really drives the number, Flutter versus two native apps, team and timeline, the yearly costs after launch, and how to compare vendor quotes.

Let’s talk

Looking for a software development partner?

Tell us about your project, what you need to build, and the challenges you are facing. We can discuss the technical approach, scope, timeline, and estimated cost.

Start a conversation