Re-platforming a monolith is the work of taking a single, large, tightly coupled application (one codebase, one deployment unit, usually one database, running everything from login to billing) and restructuring how it is built, deployed, or decomposed so that teams can change it faster and run it more safely. The phrase covers a spectrum: at the modest end, containerizing the monolith and modernizing its infrastructure without touching its structure; at the ambitious end, the famous monolith-to-microservices decomposition, carving the application into independently deployable services; and in between, the increasingly respectable middle path of the modular monolith, one deployable with enforced internal boundaries.
The reason this topic carries a decade of industry scar tissue is that the ambitious end was oversold. The 2015-2020 wave of microservices enthusiasm treated decomposition as a destination and the monolith as a confession, and produced a generation of distributed systems whose operational complexity exceeded their teams' capacity: twenty services where a well-factored monolith would do, each with its own deployment, monitoring, and failure modes, connected by network calls that used to be function calls. The correction is now part of the canon (high-profile teams have publicly consolidated services back into monoliths), and the mature framing has shifted from "monolith to microservices" as a virtue journey to a colder question: which specific parts of this system need independent deployment, scaling, or ownership badly enough to pay distribution's tax?
The honest motivations for decomposition are organizational more than technical. The monolith's real bottleneck is usually the coordination cost of many teams changing one deployable: release trains, merge conflicts at scale, the whole application redeployed for any change, one team's defect blocking everyone's release. Conway's law runs both directions: the architecture that lets twelve teams ship independently must have boundaries where the teams are, which is what service decomposition actually buys. The technical motivations (independent scaling of hot paths, isolating a risky dependency, polyglot needs) are real but rarer than cited, and a monolith serving one or two teams almost never needs decomposing at all; it needs the modest end of the spectrum (modern infrastructure, deployment automation, internal modularity), which delivers most of the value at a tenth of the risk.
The method, when decomposition is justified, has converged on the strangler fig pattern applied service by service: new or extracted capabilities run alongside the monolith, a routing layer directs traffic, and the monolith shrinks incrementally while the business keeps running, with each extraction independently shippable and reversible. The hard boundary is never the code: it is the database, where the monolith's tables are the load-bearing coupling, and splitting data ownership is where these programs spend most of their time and take most of their risk.
This page covers the decision (when decomposition pays and when it does not), the modular-monolith middle path, the strangler mechanics including the data problem, and the operational prerequisites without which microservices are a downgrade.
Diagnose before prescribing, because "the monolith is slowing us down" has at least four different referents with four different cures. Deployment pain (releases are slow, risky events): the cure is delivery engineering (CI/CD, zero-downtime deployment, feature flags), available to monoliths without any decomposition. Coupling pain (every change touches everything, regressions ripple): the cure is internal modularity, enforceable within one deployable. Scaling pain (one hot path needs capacity the rest does not): often curable by running multiple instances of the same monolith with routing, or extracting exactly one service. Team-coordination pain (ten-plus teams queuing on one release train): the genuine decomposition driver. Programs that skip this diagnosis decompose to cure deployment pain and discover they now have twenty deployment pains.
The team-count heuristic does most of the decision's work. One or two teams: the monolith is almost certainly the right architecture; invest in its infrastructure and internal structure. Three to eight teams: the modular monolith with clear internal ownership usually suffices, with perhaps one or two genuine extractions where a boundary is screamingly obvious. Beyond that, sustained: independent deployability starts paying its costs, domain by domain. The heuristic is honest because it tracks the actual benefit (coordination cost relief) rather than the imagined ones, and it explains both the big-tech success stories (hundreds of teams) and the startup graveyards (three engineers, forty services).
Price distribution's tax at full freight before signing. Every extracted service converts function calls into network calls (latency, partial failure, retries, timeouts as new failure modes), local transactions into distributed consistency problems (sagas, eventual consistency, the end of the easy join), one deployment into many (each needing pipelines, monitoring, on-call coverage), and debugging into distributed tracing. The operational floor for running microservices well (container orchestration, observability with tracing, deployment automation, on-call maturity) is a real platform investment, and teams below that floor experience decomposition as a reliability downgrade, because it is one.
Watch for the cases where decomposition is genuinely forced. A component with a wildly different risk or compliance profile (the payment path that wants PCI isolation), a dependency that cannot upgrade with the rest (the module pinned to an ancient runtime), a capability needing independent scale economics (the ML inference path on GPUs), or an acquisition integration where merging codebases is worse than federating services. These produce targeted extractions (one or two services for cause) rather than programs, and they are the right version of "partial microservices" that purists used to disparage.
And respect the null option's strength. A monolith with modern infrastructure (containers, IaC, automated zero-downtime deploys), good tests, and disciplined internal structure is a fast, cheap, operable architecture that many of the industry's best-run products ship on happily. The burden of proof sits on decomposition, not on the monolith; the monolith is not a phase the organization failed to grow out of, and the public re-consolidations of the past few years have made this respectable to say out loud again.
The modular monolith is one deployable with internal boundaries treated as seriously as service boundaries: the codebase is organized by business domain (orders, billing, catalog) rather than technical layer, each module owns its domain logic and data access, modules interact only through explicit interfaces (no reaching into another module's internals or tables), and the boundaries are enforced by tooling (build-level dependency rules, architecture tests that fail CI on violations) rather than by convention and hope. It is the discipline of microservices without the network in the middle.
What it captures of decomposition's value: independent development (teams own modules and change them without coordinating, because the interfaces are contracts), comprehensible structure (the domain map is legible in the codebase), regression containment (coupling violations are caught at build time), and, most valuably, optionality (a well-bounded module is most of the way to an extractable service, so the decomposition decision can be deferred until evidence demands it, per module). What it declines to pay: distributed failure modes, deployment multiplication, eventual consistency, and the platform floor. For the three-to-eight-team band, this trade is usually decisive.
The enforcement is the difference between a modular monolith and a monolith with folders. Unenforced boundaries erode under deadline pressure (one direct call into another module's internals, then ten, then the boundary is fiction); the working implementations make violations build failures: dependency rules in the build system, architecture-test suites, per-module ownership in code review, and database access discipline (each module its own schema or clearly owned tables, cross-module data access through the owning module's API, never raw joins across boundaries). That last rule is the one that preserves the extraction option, because shared-table coupling is precisely what makes later decomposition agonizing.
The pattern also reframes the decomposition journey for organizations that do eventually need services. The sequence with the working record: first restructure the monolith into enforced modules (hard, but all the hard parts are about understanding the domain, which decomposition would have demanded anyway), run that way and learn where the real boundaries are (module interaction patterns reveal which boundaries are stable and which were guessed wrong, at refactor cost rather than distributed-system cost), then extract the modules whose independence would pay (the hot-scaling one, the separate-team one), one at a time, with the module interface already serving as the service contract. Decomposition becomes the last step of a modularization program rather than the first step of a faith journey.
Its limits are real and worth stating: one deployable still means one release cadence ceiling (mitigated by feature flags and deploy frequency, but a fifty-team organization will eventually feel it), one runtime and language (polyglot needs require extraction), one blast radius for resource exhaustion (a memory leak anywhere is everywhere, mitigated by bulkheads but not eliminated), and scaling remains whole-application (multiple instances, not per-module). These limits are exactly the signals that tell a mature modular monolith which modules to extract, which is the system working as designed.
The strangler fig sequence is incremental by construction. A routing layer (API gateway, reverse proxy, or the monolith itself delegating) fronts the system; a capability is chosen for extraction; the new service is built and shadowed (receiving copied traffic, its outputs compared against the monolith's, the same parallel-run discipline every migration uses); traffic shifts gradually (canary-style, reversible at each step); and the monolith's implementation is eventually deleted. Each extraction is independently valuable, independently shippable, and independently abandonable, which is the property that distinguishes the pattern from the big-bang rewrite and explains its superior survival rate.
Choose extraction order by coupling, not by importance. The first extractions should be capabilities with naturally thin interfaces to the rest (notification sending, document generation, a read-heavy catalog), because the goal of the early program is proving the machinery (routing, contracts, deployment, monitoring) at low stakes. The deeply entangled core (orders, the domain everything joins against) comes last, after the team has a dozen extractions of experience and the surrounding capabilities have already been carved away, shrinking the core's tangle. Programs that start with the core because it hurts most are choosing the hardest surgery as their first operation.
The database is where the real program lives. The monolith's modules share tables; extraction requires the new service to own its data, and that split is the work: identifying which tables belong to the capability (never as clean as hoped), breaking the joins that cross the new boundary (replaced by API calls or data replication, each with consistency implications), migrating writes with the expand-and-contract discipline (dual-writing during transition, the same pattern as any live schema change), and accepting that some queries that were one join become orchestrated calls or denormalized read models. Teams consistently report the code extraction taking weeks and the data extraction taking quarters, and programs that defer the data question ("extract the code first, share the database for now") create the distributed monolith: services coupled through shared tables, combining the monolith's coupling with the network's failure modes, the worst point in the entire design space.
Transactions across the new boundary need explicit redesign, not denial. The monolith's single-database transaction (order, payment, inventory in one atomic commit) does not survive decomposition; the replacements are sagas (sequences of local transactions with compensating actions for failure), event-driven consistency (the streaming backbone carrying state changes, consumers converging), or boundary redrawing (if two things genuinely must be atomic, that is evidence they belong in the same service). The mature posture treats "where are the transaction boundaries" as a primary input to service boundaries, rather than discovering the mismatch in production as data inconsistency.
And keep the monolith healthy throughout, because it runs the business for the program's entire duration. The strangler period (years, for substantial systems) requires continued investment in the shrinking monolith (its tests, its deployability, its on-call), dual competence in the team (the people who understand the old core are the extraction program's scarcest resource, the same expert-dependency that legacy modernization fights), and resistance to the two failure modes of the middle: the stall (easy extractions done, hard core untouched, two architectures forever) and the rush (the core carved under deadline into guessed-wrong boundaries that the next five years are spent repairing). The decommissioning of the monolith's last module should be a tracked program deliverable with an owner, exactly like the data center exit in a cloud migration.
The platform floor is non-negotiable for the distributed end. Before the second service ships: container orchestration or an equivalent runtime (Kubernetes-class or serverless platforms), deployment automation with zero-downtime mechanics per service, observability built for distribution (centralized logs and metrics, distributed tracing, because "which service broke the checkout" is otherwise unanswerable), and an on-call structure that covers what is now a fleet. This floor is why decomposition is partly a platform-engineering program: organizations that fund the services but not the platform get the microservices experience everyone warns about, and the floor's cost is the strongest argument for staying modular-monolith below the team-count threshold.
Contracts between services need the same discipline as any producer-consumer boundary. Service APIs evolve additively (the backward-compatibility rules of zero-downtime deployment, applied between teams), events flowing through the backbone obey schema-registry compatibility, and breaking changes follow deprecation processes with consumer coordination: the data-contract discipline, applied to the operational plane. Teams discover that decomposition converts their internal coupling into interface governance, and the ones that formalize it early (versioning policy, contract tests in CI, consumer registries) avoid re-learning the silent-breakage lesson service by service.
Ownership must follow the boundaries or the boundaries are decoration. Each service (or module) gets a team that builds, deploys, and answers the pager for it: the you-build-it-you-run-it principle that makes independent deployability mean something. The anti-pattern is decomposition with centralized operations (one ops team paged for forty services they did not write), which recreates the coordination bottleneck at the incident layer. This is also where the SRE machinery attaches: per-service SLOs, error budgets regulating each team's velocity, production-readiness gates for each new service, so the fleet's reliability is governed rather than hoped for.
Measure the program by the outcomes that justified it. If decomposition was bought for team velocity: deployment frequency per team, lead time, and the coordination metric (how many teams does a typical change require) should visibly improve, and the DORA-style numbers are the honest scoreboard. If for scaling: the hot path's cost and headroom. If the numbers do not move after the first several extractions, the program is decomposing the wrong boundary or the bottleneck was never the monolith, and the courageous move is to pause rather than push through on sunk cost. More re-platforming programs need that pause than take it.
And expect the architecture to keep breathing. Boundaries that were right at extraction drift wrong as the domain evolves; services get merged (the re-consolidation cases are mature systems pruning over-decomposition, not retreats), split again, or absorbed back into a modular core; the platform's economics shift (serverless changing the calculus for small services, AI workloads adding new isolation needs). The end state is not a final diagram but an organization that can move capabilities across the deployment spectrum (module to service and back) at tolerable cost, which, properly understood, was the actual goal the whole time: not microservices, but cheap reversibility of architectural decisions.
The decomposition successes share a profile worth noticing. The canonical large-scale cases (Amazon's early services mandate, Netflix's migration, Uber's domain-oriented re-architecture) involved hundreds to thousands of engineers, genuine independent-scaling needs, and platform investment at a scale most organizations cannot copy: the lesson they actually teach is that decomposition pays at coordination scales most companies never reach, not that it is the path everyone should walk. Citing them in a fifty-engineer architecture review is the category error the past decade was spent committing.
The re-consolidation cases corrected the narrative. The widely discussed Prime Video team's move of one workload from distributed serverless components back into a monolithic process (for dramatic cost and performance gains) was less an indictment of microservices than a demonstration that boundaries are workload decisions, revisable on evidence; Segment's public account of collapsing dozens of per-destination services back into a monorepo and shared service told the same story at company scale: the operational overhead of fine-grained services exceeded their benefit, and consolidation was the engineering win. The teachable content is the revisability, not a new fashion in the opposite direction.
The modular-monolith exemplar is Shopify, and it is the most copied case for good reason. A massive Rails monolith, deliberately retained, restructured internally into components with enforced boundaries (dependency rules, ownership, gradual extraction only where evidence demanded, as with high-isolation domains), running one of the world's largest commerce platforms on an architecture the industry's conventional wisdom called outgrown. The case demonstrates the middle path at maximum scale: modularity as discipline rather than topology, and extraction as a per-domain evidence-based decision rather than a program.
Read together, the cases converge on the unglamorous synthesis this page has been arguing: the deployment spectrum is a dial, not a ladder; team coordination cost is the variable that should move it; the database boundary is where the real costs live regardless of direction; and the architectures that age best belong to organizations that kept the dial cheap to turn. The named cases are useful precisely because they show the dial turning both ways at companies with the engineering capacity to know why.
Restructuring how a single large application is built, deployed, or decomposed (from containerizing it unchanged, through enforced internal modularity, to incremental microservices extraction) so teams can change it faster and run it more safely.
When sustained multi-team coordination cost is the demonstrated bottleneck (roughly eight-plus teams queuing on one deployable), or when specific capabilities are forced out by scale, risk isolation, or runtime needs. Below that, modular structure and delivery engineering capture the benefits without the distributed tax.
One deployable with service-grade internal discipline: domain-organized modules, explicit interfaces, per-module data ownership, and boundaries enforced by build rules and architecture tests. It captures independent development and clean structure while deferring distribution, and each well-bounded module remains cheaply extractable if evidence later demands it.
Incremental replacement behind a routing layer: extract one capability at a time into a new service, shadow it against the monolith's behavior, shift traffic gradually and reversibly, delete the old implementation, repeat. The monolith shrinks while running the business, and each step is independently shippable and abandonable, which is why it outperforms big-bang rewrites.
Because the monolith's coupling lives in shared tables, and a real service must own its data. Splitting that ownership means breaking cross-boundary joins, migrating writes with expand-and-contract, and redesigning transactions as sagas or events. Code extracts in weeks; data extracts in quarters; and skipping the split produces the distributed monolith.
Services that are separately deployed but still coupled (shared databases, synchronized releases, chatty synchronous chains), combining the monolith's coordination cost with the network's failure modes. It is the most common bad outcome of decomposition programs, and shared tables are its leading cause.
The platform floor: container orchestration or serverless runtime, per-service CI/CD with zero-downtime deployment, observability built for distribution (centralized telemetry plus distributed tracing), schema/contract governance between services, and on-call ownership per service. Teams below this floor experience decomposition as a reliability downgrade.
Targeted extractions (one or two services for cause): a quarter or two each. Full decomposition of a substantial core system via strangler: two to five years, dominated by the data splits and the entangled core. Any plan quoting a full decomposition in months is describing the code half of the work.
The metrics that justified it move: deployment frequency per team up, lead time down, cross-team coordination per change down (DORA-style measures), or the targeted scaling/cost outcome achieved. If several extractions in, those numbers are flat, pause: the bottleneck was probably never the monolith, and more services will not find it.