Blog

Why Microservices are NOT a Good Idea

Key Takeaways

  • Don't rush into microservices. Start with a modular monolith unless independent deployment, scaling, or isolation solves a concrete problem.
  • A monolith can have clear internal boundaries. Moving those boundaries onto a network adds failure handling and operational work.
  • Independent deployment depends on compatible interfaces and clear data ownership—not separate containers or repositories.
  • Before extracting a service, budget for deployment automation, security, observability, and someone who owns production incidents.

Microservices are not a default upgrade from a monolith. They can provide valuable deployment and scaling independence, but they also introduce distributed-systems and operational costs. For a team still discovering its domain, a well-structured monolith is a better starting hypothesis than a collection of services.

Microservices have their place. The question isn't whether they work; it's whether their particular benefits justify their costs for your application and team.

Microservices vs monolith: establish a fair comparison

The monolith isn't necessarily the problem

A monolithic application typically packages its core behavior into one deployment unit. That doesn't require tangled dependencies: a modular monolith separates business capabilities behind explicit internal interfaces while deploying them together. Modules can hide implementation details without communicating over a network. Spring Modulith's module model provides a concrete example of this distinction.

With a single deployment artifact, a code fix commonly means releasing that artifact again. It doesn't mean every module changed, or that deployment must cause downtime. Likewise, a monolith can scale horizontally by running additional application instances; the trade-off is that scaling the shared unit may duplicate resources unrelated to the bottleneck. Microsoft's application architecture guide describes this deployment model.

Use this baseline rather than comparing an ideal service architecture with a badly organized monolith:

ConcernModular monolithWell-designed microservices
Internal boundariesModule interfaces inside a shared deploymentService interfaces across deployment boundaries
ReleasesShared deployment artifactIndependent releases when contracts remain compatible
ScalingUsually scales the shared application unitCan scale an individual service and its dependencies
Data operationsCan share local database transactionsCross-service operations need explicit coordination

These are architectural trade-offs, not automatic guarantees of either approach.

Microservices to the rescue—when the boundary is useful

A useful service boundary follows a business capability, such as inventory reservation or billing, rather than an arbitrary technical layer. A bounded context is the area where a particular business model and vocabulary apply. Identifying those contexts helps you decide what belongs together; it doesn't require turning every context into a separate service. Microsoft's domain analysis guidance explains this approach.

A separately deployed frontend can be useful, but putting a UI component in its own container doesn't demonstrate an independent business service. The architectural change that matters is moving responsibility across an independently operated boundary:

Modular monolith                    Microservices
request                             request
  |                                   |
[Orders module]                     [Orders service]
  | in-process call                   | network call
[Inventory module]                  [Inventory service]

Shared deployment                   Separate deployments
                                    Added network latency,
                                    partial failure, timeouts,
                                    and trace-context propagation

Docker packages and runs applications in containers; Kubernetes manages containerized workloads. Neither is a prerequisite for microservices. Services can also run on virtual machines or managed platforms, and containers can run monoliths. See our quick explanation of Docker if you need the packaging background.

What are microservices pros and cons?

Pros

Targeted scalability

Separating a resource-intensive capability can let you increase its capacity without replicating the rest of the application. For example, an image-processing service could have a different scaling policy from checkout. That benefit depends on where the actual bottleneck sits: adding service instances won't remove a shared database bottleneck.

Measure the constraint first. Compare extraction with simpler options such as query optimization, caching, additional application instances, or a separately scaled worker.

Independent deployment

A service can ship independently when its consumers remain compatible with the change. Backward-compatible interfaces, contract tests that check consumer expectations, and automated delivery make that practical. If every release requires synchronized changes across services, you've kept release coupling while adding network boundaries. Microsoft's microservices delivery guidance covers these requirements.

Technology flexibility

Different services can use different languages, runtimes, or storage technologies. That can help with a specialized workload, but every additional technology expands the team's maintenance responsibilities. Prefer a small supported technology set over unrestricted choice.

Cons

Coordination and data ownership

Services commonly own their data and expose it through interfaces rather than letting other services read and write their tables. Ownership doesn't necessarily require separate physical database servers, but shared tables create schema and release coupling. Cross-service queries may require multiple API calls or a separately maintained read model.

Transactions become harder when a business operation spans those boundaries. Consider an order that needs inventory reservation and payment: either step can succeed while the other fails. You need an explicit workflow for pending work, retries, and compensating actions—not the assumption that every update commits together.

Asynchronous events can propagate updates, but consumers may temporarily see older data. That's eventual consistency: copies converge as updates are delivered and processed. Decide where that delay is acceptable; keep tightly coupled business rules under one owner when you need a local transaction. The data management guidance covers these choices.

Even publishing an event after a database update creates a failure window. A transactional outbox stores the change and an outgoing event in one database transaction for later publication; consumers still need duplicate handling. Our event-driven vs REST microservices comparison explores the communication trade-off.

Maintainability and operating costs

Multiple repositories are not inherent to microservices. Services can live in a monorepo and still have independent deployment pipelines. Repository layout doesn't remove the work of maintaining contracts, dependencies, build processes, and production environments.

For each proposed service, estimate compute, network traffic, telemetry storage, deployment infrastructure, and engineering time. Include dependency upgrades and the extra expertise needed to operate different platforms. Targeted scaling can save resources, but those savings must outweigh the added overhead; Microsoft's compute selection guidance explicitly includes these operational trade-offs.

Networking and partial failure

A network call can be slow, unavailable, or ambiguous: the server may complete an operation even though the caller never receives its response. A checkout timeout, for example, doesn't prove that a payment failed. Long synchronous call chains also add latency and dependencies to the request path.

A monolith still has remote dependencies such as databases and external APIs. Microservices add more places where those failure modes must be handled.

Resiliency requires deliberate engineering

Set connection and request timeouts, and give the overall operation a deadline. Retry only suitable failures, bound the attempts, and use backoff with jitter—progressively delayed retries with randomness so clients don't retry together. Retries at several layers can multiply load on an already struggling dependency.

Writes need an idempotency strategy: repeating the same logical request must not repeat its business effect. Reuse the operation's idempotency key across retries, and make duplicate detection reliable. A timeout is not permission to submit a second charge. Amazon's timeout and retry guidance explains why.

Plan for overload too. Backpressure means slowing or rejecting incoming work when consumers can't keep up; unbounded queues merely postpone failure. A circuit breaker can temporarily stop calls to a failing dependency, but it adds recovery behavior you must test. Separate processes alone don't prevent cascading failures.

Holistic visibility

Centralized logs aren't enough to reconstruct a distributed request reliably. Correlate structured logs, metrics, and distributed traces: logs describe events, metrics reveal trends, and traces connect the operations involved in a request. Propagate trace context through HTTP calls and asynchronous messages. OpenTelemetry's context propagation documentation explains how this correlation works.

Monitor user-visible success and latency alongside dependency failures and queue backlog. Give incidents an operating owner, not just a dashboard. Keep credentials and sensitive customer data out of telemetry and propagated context.

Who are microservices best suited for?

Team size and application size aren't sufficient reasons to adopt services. Look for stable business boundaries, owners who can build and operate each capability, and a delivery platform that makes independent releases routine. A larger organization can still benefit from a modular monolith; a small team may justify an isolated service for a specific requirement.

When is extracting a service worthwhile?

Build a short decision record around a demonstrated need:

  • Scaling: Is one capability a measured bottleneck, and would separating it materially improve capacity or cost?
  • Releases: Do incompatible release schedules repeatedly block valuable changes?
  • Ownership: Can a team own the capability's interface, data, deployment, and incidents without constant coordination?
  • Isolation: Does it need a distinct security, resource, or failure boundary—and can you enforce that boundary?

Then compare the expected gain with migration effort and recurring operational work. Use evidence such as release delays, incident history, load tests, and infrastructure estimates. There is no universal service count or team-size threshold that replaces this assessment.

Migrate one bounded capability, not the whole system

Extraction is a migration project, not something that happens automatically as an application grows. The Strangler Fig pattern supports incremental replacement by routing selected functionality to a new implementation while the old application continues serving the rest. You don't have to extract everything.

  1. Clarify the capability's internal interface and dependencies inside the monolith first.
  2. Define its data owner, consistency requirements, and compatibility contract.
  3. Build deployment, telemetry, and failure handling before moving production traffic.
  4. Plan data backfill, validation, cutover, and recovery. Routing traffic back is insufficient if the old application no longer has current data.
  5. Measure the result and stop extracting when another service no longer earns its cost.

Keep the remainder modular. Retain focused unit tests, then add integration and contract tests where the new boundary creates risk.

Production Checklist

Before approving extraction, work through an operational readiness review. Microsoft's microservices assessment is a useful starting point.

  • Delivery: Automated builds, tests, deployments, and a rehearsed recovery procedure.
  • Connectivity: Service discovery—how callers locate services—plus explicit timeout, retry, and overload policies.
  • Security: Service identities, least-privilege access, encrypted communication, and managed secrets and configuration.
  • Operations: Named on-call ownership, runbooks, dependency maintenance, and capacity planning.
  • Data: Ownership, schema evolution, backup and restore, and cross-service consistency rules.
  • Visibility and cost: Correlated telemetry, user-facing reliability targets, and a budget covering infrastructure and engineering effort.

A managed platform can take on some infrastructure work, but it doesn't decide your business boundaries or repair an unsafe retry policy.

Don't rush into microservices

Start simple, enforce module boundaries, and extract services when evidence justifies the change. Microservices are an option for solving specific problems—not the inevitable destination of a successful application.

FAQ

Should startups use microservices?

A modular monolith is a useful default when you're still discovering the domain and the same team owns the application. Start with services only when a concrete scaling, release, or isolation requirement outweighs the operational cost.

Do microservices improve developer productivity?

They can when teams can change, test, deploy, and operate their services without coordinating every release. Shared databases, breaking interfaces, and complex local environments can erase that benefit.

Do microservices require Docker or Kubernetes?

No. Microservices can run on virtual machines, managed application platforms, or serverless infrastructure. Docker packages applications and Kubernetes manages containerized workloads; neither guarantees useful service boundaries.

When should you extract a service from a monolith?

Extract a bounded business capability when you can demonstrate an independent scaling, release, ownership, or isolation need. Define data ownership, failure behavior, an operating owner, and a migration plan before moving the boundary onto the network.

What are the hidden costs of microservices?

The costs include deployment pipelines, dependency upgrades, service authentication, secrets management, network traffic, telemetry storage, and incident response. Include engineering time and ongoing operations in the comparison, not just compute usage.

Further Reading

Written by Sam Erickson

Software engineer. I write every article on StackChief myself. Author of Mastering the Tech Interview. More about me