When Should You Actually Break Your Spring Boot App into Microservices

by Eric Hanson, Backend Developer at Clean Systems Consulting

The Wrong Reason Is Usually the First One

The most common reason teams break out a microservice is that someone read something. A conference talk, a Netflix engineering blog post, a job posting that listed microservices under requirements. The architecture gets adopted as an aspiration before there's a concrete problem it's solving.

This matters because microservices are expensive. Each extracted service adds a deployment pipeline, an observability surface, a network boundary, and an on-call surface that didn't exist before. If you can't name the specific problem that extraction solves — in terms of your actual system, your actual team, your actual traffic — you're paying that cost for nothing.

The decision framework isn't complicated. It has four legitimate triggers. If none of them are present, you don't have a reason to extract — you have a preference.

Trigger 1: Scaling Requirements Have Diverged

This is the cleanest technical justification. If one component of your application needs to scale independently from the rest — different resource profile, different scaling curve, different hardware — bundling it in the monolith forces a bad compromise.

The classic case is a video transcoding or image processing pipeline sitting inside a web application. The web layer needs low latency and horizontal scaling across many small instances. The processing pipeline needs high CPU, runs long, and scales by queue depth, not request rate. Forcing those into a single deployment artifact means either over-provisioning the web nodes or starving the processing jobs.

Before extracting, ask whether the divergence is real or projected. If your processing pipeline handles 200 jobs per day and your web tier serves 10,000 requests per day, the difference in load is real but the cost of running separate fleets may not yet be justified. The right question is: what does it cost to run a single instance of the processing component alongside the web tier, versus the operational cost of running it separately? Do that math with actual numbers before extracting.

When the numbers are concrete and the scaling profiles genuinely conflict, extraction is justified. Not before.

Trigger 2: A Team Boundary Demands It

Conway's Law is precise: the architecture of a system mirrors the communication structure of the team that builds it. The corollary is that you can use this intentionally — align service boundaries with team ownership and you get real autonomy. Misalign them and you get coordination overhead dressed up as architecture.

The signal that a team boundary is real: two groups of engineers would benefit from being able to deploy, test, and release their code without coordinating with each other. The signal that it's not real: one team owns the "service" but routinely needs sign-off from the other team to change the API contract.

Shared ownership of a service boundary is not ownership. If two teams are both modifying the same service or the same shared library that bridges services, the boundary isn't working. Extract when the boundary enables genuine autonomy — when it reduces the number of people who need to be in the same room (or Slack channel) to ship a change.

For a Spring Boot monolith with a team of 12, the right approach before extracting is often to enforce the boundary inside the monolith first. Use explicit package structure and ArchUnit rules to block cross-domain dependencies:

@AnalyzeClasses(packages = "com.example")
public class ArchitectureTest {

    @ArchTest
    static final ArchRule paymentDoesNotDependOnShipping =
        noClasses()
            .that().resideInAPackage("..payment..")
            .should().dependOnClassesThat()
            .resideInAPackage("..shipping..");
}

If the team can maintain that rule cleanly for six months, extraction becomes straightforward — the seam is already well-defined. If the rule keeps getting violated, you don't have a clean domain boundary yet, and extraction will just move the coupling across a network call.

Trigger 3: Compliance or Security Isolation Is Required

Some regulatory requirements are easier — or only possible — to satisfy with hard process boundaries. PCI DSS scope reduction is the most common example: if your payment processing logic handles raw card data, isolating it in a separate service with its own network segment, its own audit logs, and its own access controls reduces the PCI scope of the rest of your system dramatically.

Data residency requirements can create similar pressure. If user data for EU customers must stay within EU infrastructure but your system serves global traffic, a service boundary lets you route and store data independently per region without making the entire monolith region-aware.

These are legitimate non-negotiable drivers. When a compliance requirement dictates a process boundary, you extract regardless of team size or traffic volume. The cost is justified by the regulatory risk it eliminates.

Trigger 4: The Monolith's Deploy Cycle Is Blocking You

If a change to one part of the system requires deploying the entire application, and that deployment takes 20 minutes, runs a 40-minute test suite, and requires a coordinated release window — that is a real productivity cost. It compounds daily.

The honest question is whether the bottleneck is actually the monolith or the process around it. A monolith with a fast test suite, trunk-based development, and automated deployment can deploy multiple times per day without microservices. Many teams have deploy friction because of process and test suite quality, not because of architecture. Extracting a service doesn't fix a 40-minute test suite — it just means you have a 40-minute test suite per service instead of one shared one.

If you've addressed the process and the deployment coupling is still real — a database migration in the billing module causes downtime for the notifications module, or a dependency upgrade in one domain forces a coordinated release across unrelated features — then the monolith boundary is genuinely costing you. Extract the component whose deploy cycle is independent and whose release cadence is different from the rest.

The Extraction Pattern That Minimizes Risk

When one of the four triggers is present and the decision is made, extract incrementally. Don't rewrite — strangle.

The strangler fig pattern applied to a Spring Boot monolith: the new service starts by proxying through the monolith. Traffic is routed to the new service via an API gateway or load balancer rule, while the monolith remains authoritative for the data. You migrate reads first, then writes, then cut over the data ownership and retire the monolith code path.

Client → API Gateway
           ├── /payments/** → PaymentService (new)
           └── /**          → Monolith (existing)

At each step, the monolith is still running and can be fallen back to. This matters because extracted services almost always surface integration assumptions that weren't visible inside the monolith — data access patterns that don't translate cleanly across a service boundary, transaction semantics that depended on shared database state, caching behavior that assumed shared memory.

Discover those assumptions with real traffic at low blast radius, not in a big-bang cutover.

The Default Position

If you're reading this because you're planning an extraction and looking for validation — the framework is the answer. Run through the four triggers with your actual system. If you have a concrete instance of one of them, the extraction is defensible. If you're pattern-matching to justify a decision already made, that's the signal to slow down.

Microservices extracted for the right reason, at the right time, with the right team, work well. The monolith you understand completely beats the distributed system you don't — every time.

Scale Your Backend - Need an Experienced Backend Developer?

We provide backend engineers who join your team as contractors to help build, improve, and scale your backend systems.

We focus on clean backend design, clear documentation, and systems that remain reliable as products grow. Our goal is to strengthen your team and deliver backend systems that are easy to operate and maintain.

We work from our own development environments and support teams across US, EU, and APAC timezones. Our workflow emphasizes documentation and asynchronous collaboration to keep development efficient and focused.

  • Production Backend Experience. Experience building and maintaining backend systems, APIs, and databases used in production.
  • Scalable Architecture. Design backend systems that stay reliable as your product and traffic grow.
  • Contractor Friendly. Flexible engagement for short projects, long-term support, or extra help during releases.
  • Focus on Backend Reliability. Improve API performance, database stability, and overall backend reliability.
  • Documentation-Driven Development. Development guided by clear documentation so teams stay aligned and work efficiently.
  • Domain-Driven Design. Design backend systems around real business processes and product needs.

Tell us about your project

Our offices

  • Copenhagen
    1 Carlsberg Gate
    1260, København, Denmark
  • Magelang
    12 Jalan Bligo
    56485, Magelang, Indonesia

More articles

Dealing With Client Pressure Without Losing Your Mind

It starts with a “quick update?” and suddenly it’s three messages, two calls, and a new deadline. Client pressure is real—but it doesn’t have to break you.

Read more

How to Handle a Client Freaking Out Because of a Bug

Bugs happen. How you react can turn a frustrated client into a loyal one—or the opposite. Handling panic gracefully is as important as fixing the issue itself.

Read more

The Hidden Trap of Being a ‘Disguised Employee’

“You’re a contractor… but please come to the office every day.” That’s usually how it starts—then suddenly, you’re working like a full-time employee without realizing it.

Read more

From Figma to Database: The Hidden Complexity of Backend Development

Turning a Figma design into a working system sounds simple—until you reach the backend. Behind every screen lies layers of logic, data, and decisions most people never see.

Read more