All insights
CodePravaha perspective04SaaS Architecture

Your SaaS Didn’t Start as a Monolith. It Became One.

How to preserve domain boundaries, introduce microservices where they create independence, and avoid replacing a simple monolith with distributed complexity.

SaaS & ISVSeptember 2026

Most teams never decide to create an unmanageable monolith. They add features, tables, shared libraries and dependencies until every meaningful release crosses the whole product. The opposite mistake is decomposing too early and discovering a distributed monolith instead.

“Services should have loose coupling and high functional cohesion.”
Microsoft Azure Architecture Center · Microservices ↗

The market signal

Microsoft’s microservices guidance stresses loose coupling, cohesion, independent deployment, data ownership and failure isolation. AWS recommends understanding business capabilities and dependencies before decomposing a monolith, and documents patterns such as decomposition by business capability and the Strangler Fig. Martin Fowler’s “Monolith First” argument remains useful because service boundaries are expensive to get wrong.

The balanced conclusion: architect for independence before optimizing for service count.

How the accidental monolith forms

The early product chooses one runtime, one database and one deployment because that is the fastest path to MVP. Those choices are reasonable. The problem begins when every new domain keeps sharing the same schema, internal libraries, release train and scaling model long after the product has multiple teams and distinct workloads.

A system can also have 40 containers and still be a monolith if they must deploy together, share the same database and call one another synchronously for every request.

How stronger product companies handle it

Anti-patternWhat it really signalsBetter response
Many services deploy togetherDistributed monolithRevisit boundaries and independent deployment
Shared database schemaData couplingExplicit domain ownership before physical separation
Every team chooses a stackOperational sprawlOpinionated default + justified exception
One stack mandated foreverWorkload constraintPermit exceptions when economics or workload justify them
Kubernetes required for everythingPlatform complexity leaked to teamsGolden paths and simpler managed services where appropriate

The CodePravaha perspective

Use an Architecture Independence Ladder: Code boundaries → domain modules → explicit data ownership → independent deployment → independent scaling → justified technology choice.

The operating rule is Opinionated Default + Justified Exception. Give teams a preferred runtime, CI/CD, observability, secrets, API and infrastructure path. Allow deviation when a workload has a real technical or business need, not because every team wants a different tool.

When a module deserves to become a service

Extract when several of these are true: a distinct team owns it; it changes at a different cadence; it needs independent scale or availability; failures should be isolated; it has a clear business boundary; a different data technology is materially better; it can own its data; and it can deploy without coordinating with the core application.

If almost all answers are “no,” a modular component inside the existing deployable may be the simpler architecture.

What to change now

Map business domains and dependencies before drawing service boundaries.
Enforce modular boundaries and explicit data ownership inside the current codebase.
Define a preferred engineering stack and golden path for common workloads.
Use a service-extraction test based on ownership, scale, reliability and change cadence.
Extract incrementally using routing/strangler patterns rather than big-bang rewrites.
Add observability and failure isolation before increasing distribution.

Metrics worth watching

Measure cross-team release dependencies, repositories/services touched per customer feature, percentage of independently deployable components, change failure blast radius, scaling cost by workload, shared-schema changes, synchronous dependency depth and developer time spent operating infrastructure rather than product capabilities.

CodePravaha takeaway

Use an opinionated default stack, modular domain boundaries and a service-extraction test. Separate only when business ownership, scaling, reliability or change cadence justify it.

Sources & further reading

Which part of this is slowing your product?

Start a conversation.

We will use the first conversation to understand the constraint and decide whether the useful next step is advice, a focused assessment, an engineering engagement or no engagement at all.

Start a conversation