Remember the story from the tRPC lesson: the title field was renamed to heading, the server works, the tests are green, but users' apps lost their headings? tRPC protects against this kind of trouble inside one project. But what if Leyla's web and Murad's api live in different repositories and do not even use tRPC? In this lesson you will learn what a monorepo is, how it differs from a set of separate repositories (polyrepo), how it is organized, and when you do not need one.
The problem: two repositories, one product
Leyla writes notes-web, Murad writes notes-api. These are two repositories with their own package.json files, linter rules, CI and releases. Both need the Note type, so in March Leyla copied it to her side. In April Murad renamed the field:
// notes-api/src/types.ts (Murad renamed the field in April)
export type Note = { id: string; heading: string };
// notes-web/src/types.ts (Leyla copied the type in March)
export type Note = { id: string; title: string };Each repository is fine on its own: the types match, the tests pass, CI is green. Only a user will find the bug, when they see empty headings. This approach has typical pains.
- Copies of code. Types, data validation schemas and small functions get copied from repository to repository — and the copies drift apart.
- Diverging versions. One project has
zod3, another haszod4, and each has its owntsconfigand ESLint rules. - Changes across several repositories. One fix means two pull requests in different places, an agreement on the merge order and a coordinated release.
- Slow onboarding. A newcomer clones and sets up N repositories and learns N sets of rules.
What a monorepo is
A monorepo is a single Git repository that holds several projects: applications and libraries that may depend on each other. Every project stays a separate package with its own package.json.
Picture an apartment building and a set of separate houses. The building has a shared foundation, an elevator and heating — these are shared tools and shared code. But every apartment has its own door and its own walls — these are the boundaries between packages. In separate houses everybody fixes their own pipes.
⚠️ A monorepo is not a monolith. A monorepo answers the question "where is the code stored", a monolith answers "how is the code deployed". In a monorepo
webandapiare still separate applications with separate deployments. A separate topic of the course covers monoliths and microservices.
In a monorepo the same story ends differently. The type is described by a shared package, and both sides plug it in instead of copying it: