Case study
From microservices to a monolith.
A LegalTech platform split into many NestJS services, and a team of about a dozen people. We are bringing it back together into a monolith, in a single repository.
- Role
- Architecture decision and migration lead
- Team
- Engineering, QA, Infrastructure
- Tools
- pnpm workspaces, Turborepo, Biome, Storybook, Cypress
- Status
- In progress
01Where we started
The platform grew one service at a time: one service per business domain, each with its own repository, configuration and pipeline. The split made sense at first. Over time, it mostly multiplied what we had to maintain.
A single business change often spans several services, which means coordinating several repositories, versions and deployments for one feature. Configuration, linting and dependencies drift from one service to the next, and every security update has to be repeated in each repository.
02The decision
Microservices solve organizational problems we don't have: several autonomous teams shipping independently, or very different scaling needs across domains. For a single product team, they cost more than they give back.
We chose a monolith in a pnpm monorepo driven by Turborepo. One repository, one validation pipeline, and module boundaries enforced by tooling instead of by the network.
03The rules of the repository
A monolith without rules quickly turns back into spaghetti. We set a few, written down in the repository and checked in CI.
An app never imports another app
Code shared between applications lives in a package. A package never depends on an app.
No speculative packages
We only extract a package when a second consumer shows up. No abstractions just in case.
One validation pipeline
Formatting, linting, type checking and test coverage run in every workspace before each commit, exactly as in CI.
Decisions in writing
Every structural choice gets an ADR, and the business vocabulary lives in a shared glossary.
04How we migrate
No big bang. The new repository first took in the client front end, with its design system, tests and pipeline. The other applications and the back end join it one at a time, while the existing platform keeps running.
Every step has to leave the platform shippable. It is slower on paper, but clients never notice the migration and the team keeps delivering the roadmap alongside it.
05What I take away
The architecture choice matters less than the rules that come with it. A monorepo without enforced boundaries is no better than badly split microservices.
Part of my job is to make those rules obvious to the team: written next to the code, checked automatically, and explained in reviews rather than imposed.