Помните историю из урока про tRPC: поле title переименовали в heading, сервер работает, тесты зелёные, а у пользователей в приложении пропали заголовки? tRPC защищает от такой беды внутри одного проекта. Но что, если web Лейлы и api Мурада живут в разных репозиториях и даже не используют tRPC? В этом уроке вы узнаете, что такое монорепозиторий, чем он отличается от набора отдельных репозиториев (polyrepo), как он устроен и в каких случаях он вам не нужен.

Проблема: два репозитория — один продукт

Лейла пишет notes-web, Мурад — notes-api. Это два репозитория со своими package.json, правилами линтера, CI и релизами. Тип Note нужен обоим, поэтому Лейла в марте скопировала его к себе. В апреле Мурад переименовал поле:

ts
// 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 };

Каждый репозиторий по отдельности в порядке: типы сходятся, тесты проходят, CI зелёный. Ошибку найдёт только пользователь, когда увидит пустые заголовки. У такого подхода есть типичные боли.

  • Копии кода. Типы, схемы проверки данных и мелкие функции копируют из репозитория в репозиторий — и копии расходятся.
  • Расхождение версий. В одном проекте zod третьей версии, в другом четвёртой, у каждого свои tsconfig и правила ESLint.
  • Изменения через несколько репозиториев. Одна правка — это два pull request в разных местах, договорённость о порядке слияния и согласованный релиз.
  • Долгое знакомство. Новичок клонирует и настраивает N репозиториев и изучает N наборов правил.

Что такое монорепозиторий

Монорепозиторий (monorepo) — один Git-репозиторий, в котором лежат несколько проектов: приложения и библиотеки, которые могут зависеть друг от друга. Каждый проект остаётся отдельным пакетом со своим package.json.

Представьте многоквартирный дом и отдельные частные дома. В доме общий фундамент, лифт и отопление — это общие инструменты и общий код. Но у каждой квартиры своя дверь и свои стены — это границы между пакетами. В частных домах каждый чинит свои трубы сам.

Слева два репозитория с копиями типа, справа один репозиторий с общим пакетом
Слева два репозитория с копиями типа, справа один репозиторий с общим пакетом

⚠️ Монорепозиторий — не монолит. Монорепо отвечает на вопрос «где хранится код», монолит — на вопрос «как код выкладывают». В монорепо web и api по-прежнему отдельные приложения с отдельным развёртыванием. Про монолит и микросервисы расскажет отдельная тема курса.

В монорепо та же история заканчивается иначе. Тип описывает общий пакет, и обе стороны подключают его, а не копируют: