Разбираем, когда монорепо для web, API и mobile помогает команде и ИИ: плюсы и минусы, критерии выбора, чеклист и пример проекта.

Монорепо - это когда web, API и mobile живут в одном репозитории: одна история изменений и общие правила. Выбор между полирепо и монорепо - не про моду. Он про то, как часто части продукта меняются вместе и сколько времени уходит на согласование.
Обычно к общему репозиторию приходят не из любопытства, а из боли: одна и та же валидация повторяется в web и mobile и со временем расходится; API поменяло поле, а фронт узнал об этом после релиза; тесты падают только в одном месте, потому что версии библиотек разъехались.
Монорепо особенно помогает, когда нужен общий контекст. В одном месте проще увидеть изменения, которые идут пакетом: обновили контракт API, поправили типы, обновили экран в приложении и тесты. Меньше мелких договоренностей в чатах и созвонах.
Тема «удобно для ИИ» здесь приземленная: дело не в магии, а в структуре и правилах. Любой помощник, будь то в редакторе или в vibe-coding платформе вроде TakProsto, работает точнее, когда проект предсказуем: понятно, где лежат модули, где контракт API, и какими командами запускаются сборка и тесты.
Часто завышают ожидания в двух местах. Во-первых, ждут, что монорепо само уберет конфликты и ускорит сборку. Во-вторых, надеются, что один репозиторий автоматически приведет к «общему коду» между фронтом и бэком. На практике общий код возможен не всегда: у web, Go API и Flutter разные языки, окружение и ограничения.
Монорепо дает выигрыш, только если заранее договориться о границах: что действительно общее (например, спецификация API, тестовые данные, правила линтинга), а что остается отдельным. Без этого монорепо превращается в большой склад файлов.
Монорепо полезно там, где у частей продукта есть общий смысл и общие правила, а не просто общий репозиторий «для галочки». Для web (React), API (Go) и mobile (Flutter) реально объединить «язык продукта»: что такое пользователь, заказ, статус; какие поля обязательны; какие ошибки возвращаем.
Обычно в общее выносят доменные модели и перечисления (статусы, роли), контракты API (OpenAPI/JSON Schema и примеры), часть утилит (например, форматирование денег и дат), а также автогенерируемые клиенты и типы, чтобы фронт и мобильный клиент не гадали.
При этом многое почти всегда разное: зависимости, сборка и запуск, рантайм (браузер, сервер, устройство), UX и сетевые ограничения. Если попытаться «склеить» все в один слой, сложность начнет съедать пользу.
Простая структура, которая часто работает: apps и packages. В apps - три самостоятельных приложения (web, api, mobile). В packages - переиспользуемые куски с четкими границами.
Внутри конкретного приложения лучше оставлять UI-экраны и компоненты, настройки сборки и окружений, а также интеграции и инфраструктурный код (логирование, метрики, доступ к БД).
Контракты API и командные договоренности удобно хранить рядом с кодом, но отдельно: единый пакет со схемами плюс папка с короткими правилами (как именуем поля, как версионируем, какие статусы ошибок используем). Так и люди, и ИИ видят один источник правды.
Главный плюс - один источник правды. Когда web, API и mobile живут рядом, проще держать в порядке типы, схемы и контракты: меньше ситуаций «где последняя версия» и «почему у клиента поле называется иначе, чем в API».
Это особенно заметно на сквозных изменениях. Допустим, вы переименовали поле user_status в status. В монорепо вы меняете контракт и связанные модели, а затем сразу видите, что сломалось в React-приложении, в Go-сервисе и во Flutter. Ошибки всплывают на проверках сразу, а не через неделю в проде.
Еще один плюс - единые правила качества кода. Общие настройки форматирования, линтинга и тестов снижают «споры о стиле» и помогают держать одинаковый уровень аккуратности в разных частях продукта.
Из того, что ощущается каждый день: сквозные правки делаются быстрее, дублирование утилит уменьшается, а онбординг проще, потому что структура и команды в одном месте.
Монорепо часто выглядит как «одна папка и порядок». На практике порядок не появляется сам. Вы получаете общий контекст ценой более жесткой дисциплины и более сложных проверок.
Первый счет обычно приходит в сборке и CI: в одном репозитории неочевидно, что именно пересобирать после маленького изменения. Если нет понятных правил зависимостей и кеширования, любой коммит начинает запускать все подряд, а ожидание растет.
Вторая боль - зависимости. В монорепо легко «заразить» один проект решениями другого: общая версия библиотеки, общий линтер, общие утилиты. Это удобно, пока не появляется конфликт: мобильному приложению нужна одна версия пакета, а web - другая.
Третья цена - обратная связь. Без строгих границ изменения начинают задевать слишком много кода. Проверки становятся длиннее, а команда перестает доверять красным тестам: «опять сломалось где-то не у нас».
Чтобы минусы не съели плюсы, обычно помогают простые, но обязательные вещи: явные границы модулей и правила импортов, владельцы зон (кто одобряет изменения в shared-коде), сборка «только затронутого» и кеширование, а также понятная политика версий для общих пакетов.
Даже если вы генерируете код через чат, монорепо не отменяет ответственность. ИИ легко предложит правку «в общем месте», которая затронет все приложения. Без границ и владельцев такая правка быстро превращается в цепочку неожиданных поломок.
ИИ дает лучший результат, когда видит цельную картину. Монорепо для web, API и mobile помогает именно этим: рядом лежат контракты, примеры запросов, модели данных и реальный код, который их использует. Тогда подсказки и генерация ближе к правде, а не к «догадкам по описанию».
Самая заметная выгода появляется, когда вы держите рядом API-спецификацию (или хотя бы папку с примерами запросов и ответов) и код клиентов. ИИ проще сопоставляет поля, статусы ошибок и правила валидации, потому что быстро находит подтверждение в тестах и фикстурах.
Чтобы ИИ не терял нить, нужны жесткие соглашения. Если папки и имена живут по настроению, модель начинает «склеивать» разные части системы и предлагать странные правки. Работают простые опоры: стабильные названия каталогов, единый стиль именования DTO и ошибок, одна команда для тестов и одна для линтера, а также «живые» примеры рядом с контрактами.
Ключевой момент - заранее описать границы модулей. Например: shared содержит только типы и чистые функции, без доступа к базе и без HTTP-клиентов. Иначе ИИ легко смешает слои: предложит дергать PostgreSQL из мобильного кода или протащит React-зависимости в общий пакет.
Пример: вы добавляете поле promoCode в заказ. В монорепо ИИ быстрее находит тип Order, валидатор в Go, экран оформления во Flutter и тесты, и вносит согласованные изменения без расхождений в названиях и форматах.
Выбор обычно упирается не в идеологию, а в то, как вы работаете каждый день. Монорепо для web, API и mobile чаще всего оправдано там, где изменения идут «сквозняком»: поправили модель данных, и следом нужно обновить API, веб-формы и мобильные экраны.
Первый ориентир - размер команды и частота таких сквозных правок. Если у вас 2-6 человек и вы часто трогаете одни и те же сущности, монорепо снижает потери на согласования и разъезды версий. Если команд много и они почти не пересекаются, полирепо обычно проще поддерживать.
Второй критерий - насколько важно повторное использование моделей и договоренностей. Когда это реально экономит время (контракты, справочники, форматы ошибок, одинаковая валидация), единый репозиторий помогает не плодить «почти одинаковые» реализации.
Третий - релизы. Если вам нужен единый релизный цикл (выпускаем фичу целиком), монорепо удобнее. Если мобильное приложение живет своим ритмом, а API деплоится отдельно и часто, независимые репозитории могут дать меньше трения.
Перед решением стоит честно проверить базовые условия: есть ли код-ревью и автотесты, можно ли ограничить права на критичные части, понятна ли ответственность за API, web и mobile, и сможете ли вы не смешивать секреты и окружения.
Простой пример: дизайнер поменял поля профиля пользователя. В монорепо вы одним PR обновляете схему, сервер, веб и Flutter-экраны. В полирепо это часто превращается в 3-4 PR и риск, что один из клиентов уедет «в прошлое».
Переход проще делать как проект с понятной областью работ, а не как «перенести все и сразу». Сначала договоритесь, что именно хотите получить: общий контекст, повторное использование кода или единые проверки.
Начните с инвентаризации того, что реально общее и дает пользу. Обычно это схемы API и модели данных, клиент для запросов, справочники, часть утилит и правила валидации. Если «общее» нельзя использовать минимум в двух приложениях без боли, лучше не тащить это в shared.
Дальше опишите границы модулей. У каждого пакета должен быть владелец (команда или конкретные люди), а у изменений - понятные правила: кто одобряет правки в общих библиотеках и кто отвечает за поломки.
Короткая последовательность, которая часто работает:
apps и packages) и правило зависимостей: приложения тянут библиотеки, но не наоборот.Полезно начинать с малого: сначала вынести общий пакет с контрактами или моделями и договориться о правилах, а приложения переносить по одному.
Проблемы обычно появляются не из-за формата репозитория, а из-за отсутствия правил.
Классика: фронт начинает напрямую тянуть серверный код, модели БД или доменную логику без оговоренных границ. Сначала это кажется быстрым решением, а через месяц любое изменение на бэке ломает сборку веба или мобильного приложения.
Практичное правило: общий код - это либо типы/контракты, либо «чистые» библиотеки без привязки к инфраструктуре (без сетевых клиентов, без доступа к базе, без зависимостей на фреймворк).
Если API меняется вместе с клиентами в одном репозитории, возникает соблазн: «поправлю и фронт, и бэк одним коммитом». Проблемы начинаются, когда части деплоятся по разным графикам (например, мобильное приложение обновляется медленно через сторы). Без явных контрактов и политики версий вы получите тихие поломки.
Минимум, который спасает: один источник правды для контрактов, правило совместимости изменений (что считается breaking), и отдельная версия для API и для клиентов, даже если код рядом.
В монорепо быстро появляется папка вроде shared/common, куда складывают все подряд. Без владельца и критериев входа это превращается в залежи кода, которые страшно трогать.
Назначьте владельца и заведите простое правило: нет понятного пользователя и тестов - значит, это не общий пакет.
Монорепо не обязано быть медленным. Но если никто не смотрит на время проверок, оно растет незаметно. Особенно больно, когда изменения часто затрагивают несколько пакетов, и каждый коммит запускает лишнее.
Типичный сценарий: мобильное приложение подтянуло веб-зависимость, потому что «там удобный хелпер». Или наоборот. Итог - конфликты версий и странные ограничения.
Держите явные границы по платформам и проверяйте зависимости автоматически: общий код - только кроссплатформенный, платформенный живет отдельно.
Монорепо для web, API и mobile обычно работает лучше всего, когда у команды есть общий «скелет» продукта: единые договоренности по данным, понятные границы модулей и дисциплина по изменениям.
Если уверенно отвечаете «да» хотя бы на 4 пункта из 5, монорепо, скорее всего, будет помогать:
Пример: вы добавляете поле в модель «Заказ». В монорепо легко увидеть, где это поле используют web, API и mobile. Но это работает только если контракты лежат в одном понятном каталоге, а зависимости не хаотичные.
Представьте стартап: есть web-кабинет, отдельное API и мобильное приложение. Команда небольшая, задачи летят быстро, а менять продукт нужно без недельных согласований. Кажется логичным держать все рядом.
Проблема всплывает на мелочах. Появляется новое поле, например deliveryMethod, и бизнес-правило: при самовывозе адрес обязателен только для определенных городов. Через неделю вы находите три версии одной логики:
Ошибки тут не «в коде», а в рассинхроне. Ревью превращается в угадайку: проверили ли вы все места, где поле живет.
Рабочее решение обычно не в том, чтобы смешать все в одну сборку, а в том, чтобы вынести общее в отдельный пакет внутри репозитория. Сборки остаются раздельными (web отдельно, API отдельно, mobile отдельно), но источник правды лежит рядом: модели и DTO, схемы запросов и ответов, общие правила валидации, утилиты форматирования.
На практике это означает простую вещь: меняете правило один раз и сразу видите, какие части сломались. Изменения идут одним набором коммитов, а не тремя несвязанными PR.
После выбора монорепо важно не «победить» один раз, а сделать так, чтобы подход жил в команде. Иначе быстро появятся обходные пути, временные папки и хаос в зависимостях.
Начните с четкой цели: что именно вы хотите упростить - согласование контрактов, переиспользование типов, релизы, онбординг или проверки. Одна цель на старт дает понятный критерий успеха.
Дальше сделайте маленький пилот: выберите один общий пакет (например, схемы API или модели домена) и проведите одно сквозное изменение от контракта до обновления web и mobile с проверкой в CI.
Чтобы не откатиться, зафиксируйте правила в коротком документе на одну страницу: что можно импортировать, кто владеет пакетами, как выпускаются версии, какие проверки обязательны, и что делать при срочном хотфиксе.
Если вы работаете в TakProsto, полезно сразу закрепить структуру и ограничения в контексте проекта: это снижает риск, что генерация начнет создавать лишние папки или смешивать слои. В самой платформе удобно пройти Planning Mode, а затем экспортировать исходники; при неудачном эксперименте выручат snapshots и быстрый откат. Для справки: официальный сайт - takprosto.ai.
Раз в 2-3 недели стоит делать короткий обзор: где растут лишние связи, где копируется код, и что тормозит релизы. Это дешевле, чем потом спасать структуру большим рефакторингом.
Если у вас часто бывают сквозные изменения (поменяли модель или поле — нужно сразу поправить API, web и mobile), монорепо обычно экономит время. Если части продукта живут почти независимо и релизятся отдельно, несколько репозиториев часто проще.
Чаще всего причина — рассинхрон. Один и тот же контракт, валидация или формат ошибки со временем расходятся между web, API и mobile, и это всплывает уже после релизов. Монорепо помогает держать один «источник правды» рядом с кодом.
Рабочий минимум — контракты API (например, OpenAPI/JSON Schema), примеры запросов и ответов, общие справочники (статусы, роли), а также автогенерируемые клиенты/типы. Это дает согласованность без попытки «склеить» разные платформы в один код.
UI, сборка, конфиги окружений, интеграции, работа с БД, логирование и метрики обычно должны оставаться внутри конкретного приложения. Общий пакет должен быть максимально «чистым», иначе изменения начнут цеплять слишком много мест и замедлят разработку.
Базовая структура — apps для приложений (web/api/mobile) и packages для переиспользуемых модулей. Важно заранее закрепить правило зависимостей: приложения могут зависеть от пакетов, а пакеты не должны тянуть код приложений.
Монорепо не ускоряет сборку автоматически. Чтобы не запускать «всё подряд», нужен CI, который собирает и тестирует только затронутые части, плюс кеширование. Без этого ожидание проверок обычно растет вместе с репозиторием.
Главный риск — общий код превращается в место, куда складывают всё, потому что «так удобно». Лечится простыми правилами: у каждого общего пакета есть владелец, понятный критерий добавления и тесты, иначе общий код становится хрупким и страшным.
Монорепо помогает ИИ, когда проект предсказуем: понятные каталоги, единый источник контрактов, одинаковые команды для тестов и линтинга. Но ИИ легче ошибается именно в монорепо, если не описаны границы модулей и правила импортов.
Даже если код рядом, графики релизов могут отличаться, особенно у мобильного приложения. Поэтому полезно иметь явную политику совместимости изменений API (что считается breaking) и версионирование контрактов, чтобы не ломать старые клиенты.
Начните с малого: вынесите в монорепо один «источник правды» (например, схемы API и типы), настройте базовые проверки и проведите одно сквозное изменение от контракта до UI и тестов. Перенос приложений по одному обычно спокойнее, чем миграция «всё и сразу».