Microservices or Modular Monolith? A Decision Guide for Spring
Deciding between microservices and a modular monolith: the distributed systems tax, team-scale criteria, module boundaries with Spring Modulith, decomposition signals and the strangler fig strategy.
Microservices or a modular monolith?
For most teams the right starting point is a modular monolith: a single deployment unit with sharply drawn boundaries and enforced internal dependencies. Microservices are earned later, by splitting along those boundaries when specific scale and organizational signals appear — they are not a day-one goal. This article moves the decision from slogans to measurable criteria.
The real cost of microservices: the distributed systems tax
Microservices move the module-boundary problem to a network boundary and attach a tax package: latency and partial-failure scenarios on every remote call; data consistency leaving transaction guarantees for saga/outbox patterns; separate deployment, monitoring, logging and alerting per service; and API contract versioning discipline. The tax is worth paying when independent scaling and independent deployment outweigh it — for small and mid-sized teams they usually do not.
The decision table: which architecture do your signals point to?
Criterion | Modular monolith suffices | Microservice signal |
|---|---|---|
Team structure | One product team / a few squads | Many teams needing independent lifecycles |
Deployment need | A shared release cadence is fine | Domains must ship at different speeds and risk levels |
Scaling profile | Load is largely homogeneous | Specific domains (e.g. search, cart) need independent scaling |
Data consistency | Strong consistency is business-critical | Eventual consistency fits the business rules |
Operational maturity | CI/CD and observability still forming | Automation and monitoring mature, team experienced with distribution |
Building a modular monolith: boundaries enforced in code
A modular monolith succeeds through enforceable boundaries, not intentions. In the Spring ecosystem the current tool is Spring Modulith: the application is split into domain modules; modules cannot reach into each other's internals, and communication flows through explicit APIs and application events. Boundary violations fail the build via Modulith's verification tests or ArchUnit rules — architecture becomes a compile-breaking contract rather than a slide-deck diagram. The same structure is a rehearsal for future service boundaries: a well-drawn module is the one that later becomes a service at the lowest cost.
Is it time to split? Four concrete signals
First, scale asymmetry: when one domain's resource needs make scaling the whole wasteful, that domain is a candidate. Second, release-cadence conflict: when one area wants to ship several times a day and another once a month, the shared deployment unit becomes a brake. Third, team scale: as the number of teams waiting on each other in one codebase grows, coordination cost grows super-linearly. Fourth, failure isolation: when instability in one domain must not take down the whole, the boundary moves to the network. Without a signal, splitting is cost without benefit.
Migration strategy: strangler fig, not big bang
The proven pattern for moving from monolith to services is the strangler fig approach named by Martin Fowler: a new service takes over domain by domain behind a routing layer placed in front of the monolith; traffic shifts gradually, and old code is deleted only when its traffic reaches zero. The critical precondition is clarified data ownership for the domain being extracted — a 'service' where both sides write to a shared table is nothing but a distributed monolith. During migration, change data capture (CDC) or outbox patterns preserve consistency better than dual writes.
Business impact: an architecture decision is a hiring and budget decision
The microservice decision is never purely technical: every service means a pipeline, an on-call rotation and a monitoring dashboard, and that burden lands on the team plan, the cloud bill and the hiring profile. A modular monolith usually carries the same business value with a smaller team and a lower cloud cost; microservices, with the right signals, buy scalability and team autonomy. We advise clients to test the decision with one question: "Which concrete bottleneck will this split prevent in the next 12 months?" If there is no answer, the answer is the monolith.
Frequently asked questions
Is a modular monolith 'old-fashioned'?
No — as the costs of the microservice wave became visible, the modular monolith returned to mainstream recommendation; the emergence of tools like Spring Modulith is a product of that shift.
Should I never move to microservices?
Move when the signals are there: asymmetric scale, conflicting release cadences, a multi-team organization. What is wrong is starting without signals — by architectural fashion.
Is event-driven architecture mandatory?
Event-based communication at module/service boundaries buys loose coupling; but turning every interaction into an event can hurt readability. Synchronous for commands/queries, events for propagating state is a practical balance.
Can microservices share one database?
Schema-level ownership separation is acceptable during transition; the lasting goal is each service's data accessed only through its API. Multi-service writes to shared tables produce a distributed monolith.
Decision checklist
Domain boundaries identified and reflected in module structure
Module boundaries enforced in CI (Spring Modulith / ArchUnit)
Inter-module communication limited to APIs + events
Decomposition signals (scale, cadence, teams, isolation) reviewed regularly
Data ownership of candidate modules is clear
Migration plan defined incrementally via strangler fig
Operational cost of each new service budgeted
SSH Yazılım provides architecture assessment, modularization and microservice migration planning for enterprise Java/Spring projects. Let us ground your architecture decision in data.