PurpleSchool — курсы программирования онлайн
  • Бесплатно
    • Курсы
    • JavaScript Основы разработкиPython Основы PythonCSS CSS FlexboxКарта развития
    • База знанийИконка стрелки
    • Новостные рассылкиИконка стрелки
  • Карьерные пути
    • Frontend React разработчик
    • Frontend Vue разработчик
    • Backend разработчик Node.js
    • Fullstack разработчик React / Node.js
    • Mobile разработчик React Native
    • Backend разработчик Golang
    • Devops инженер
    • Backend разработчик Python
  • О нас
    • Отзывы
    • Реферальная программа
    • О компании
    • Контакты
  • Иконка открытия меню
    • Сообщество
    • PurpleПлюс
    • AI тренажёр
    • Проекты
PurpleSchool — платформа бесплатных roadmap и курсов для разработчиков
ютуб иконка
Telegram иконка
VK иконка
VK иконка
Курсы
ГлавнаяКаталог курсовFrontendBackendFullstack
Практика
КарьераПроектыPurpleПлюс
Материалы
БлогБаза знаний
Документы
Договор офертаПолитика конфиденциальностиПроверка сертификатаМиграция курсовРеферальная программа
Реквизиты
ИП Ларичев Антон АндреевичИНН 773373765379contact@purpleschool.ru

PurpleSchool © 2020 -2026 Все права защищены

  • Курсы
    • FrontendИконка стрелки
    • AI разработкаИконка стрелки
    • BackendИконка стрелки
    • DevOpsИконка стрелки
    • MobileИконка стрелки
    • ТестированиеИконка стрелки
    • Soft-skillsИконка стрелки
    • ДизайнИконка стрелки
    Иконка слояПерейти в каталог курсов
  • PurpleSchool — курсы программирования онлайн
    • Сообщество
    • PurpleПлюс
    • AI тренажёр
    • Проекты
    Главная
    Сообщество
    Монорепозиторий на Turborepo: как организовать фронт и бэк в одном репо

    Монорепозиторий на Turborepo: как организовать фронт и бэк в одном репо

    Аватар автора Монорепозиторий на Turborepo: как организовать фронт и бэк в одном репо

    Антон Ларичев

    Иконка календаря10 апреля 2026
    typescriptreactnodejsmiddleИконка уровня middle
    Картинка поста Монорепозиторий на Turborepo: как организовать фронт и бэк в одном репо

    Введение

    Монорепозиторий на Turborepo позволяет объединить фронтенд и бэкенд в одном репозитории, сохраняя при этом четкое разделение ответственности и высокую скорость сборки. Если вы работаете с React и NestJS, такая организация проекта ускоряет разработку за счет переиспользования типов, утилит и конфигураций между приложениями.

    В этой статье разберем, как организовать фронтенд и бэкенд в одном репо с помощью Turborepo, настроить workspace, общие пакеты и pipeline задач. Покажем реальную структуру проекта, которую можно сразу применить в продакшне.

    Почему монорепозиторий на Turborepo, а не мультирепо

    Когда фронтенд и бэкенд живут в разных репозиториях, появляются типичные проблемы: дублирование типов, рассинхронизация API-контрактов, сложность локальной разработки. Монорепозиторий решает их, но без правильного инструмента превращается в медленный монолит.

    Turborepo решает проблему производительности через:

    • Инкрементальные сборки — пересобираются только измененные пакеты
    • Кэширование результатов — повторные сборки завершаются мгновенно
    • Параллельное выполнение — независимые задачи запускаются одновременно
    • Pipeline задач — turbo.json описывает зависимости между задачами

    В отличие от Nx, Turborepo не требует плагинов и сложной конфигурации. Вы описываете задачи в turbo.json и продолжаете использовать привычные скрипты package.json.

    Структура монорепозитория: apps и packages

    Стандартная структура Turborepo проекта разделяет код на два каталога:

    monorepo/
    ├── apps/
    │   ├── web/              # Next.js фронтенд
    │   └── api/              # NestJS бэкенд
    ├── packages/
    │   ├── shared-types/     # Общие TypeScript типы
    │   ├── ui/               # UI-компоненты (React)
    │   ├── config-eslint/    # Общая конфигурация ESLint
    │   └── config-typescript/# Общий tsconfig
    ├── turbo.json
    ├── package.json
    ├── pnpm-workspace.yaml
    └── .gitignore
    

    Каталог apps/ содержит приложения — это то, что деплоится. Каталог packages/ содержит общие библиотеки, которые используются приложениями как зависимости.

    Как настроить Turborepo с pnpm с нуля

    Начнем с инициализации проекта. Используем pnpm как пакетный менеджер — он лучше всего работает с workspace:

    # Создаем проект
    npx create-turbo@latest my-monorepo
    cd my-monorepo
    

    Если настраиваете вручную, создайте корневой package.json:

    {
      "name": "my-monorepo",
      "private": true,
      "scripts": {
        "build": "turbo run build",
        "dev": "turbo run dev",
        "lint": "turbo run lint",
        "test": "turbo run test"
      },
      "devDependencies": {
        "turbo": "^2.0.0"
      },
      "packageManager": "pnpm@9.0.0"
    }
    

    И pnpm-workspace.yaml:

    packages:
      - "apps/*"
      - "packages/*"
    

    Настройка turbo.json для фронтенда и бэкенда

    Файл turbo.json описывает pipeline — какие задачи запускать и как они зависят друг от друга:

    {
      "$schema": "https://turbo.build/schema.json",
      "tasks": {
        "build": {
          "dependsOn": ["^build"],
          "outputs": ["dist/**", ".next/**"]
        },
        "dev": {
          "cache": false,
          "persistent": true
        },
        "lint": {
          "dependsOn": ["^build"]
        },
        "test": {
          "dependsOn": ["build"]
        }
      }
    }
    

    Символ ^ в dependsOn означает: сначала собери зависимости пакета, потом сам пакет. Это гарантирует, что shared-types соберется раньше, чем web или api.

    Общие типы между фронтендом и бэкендом

    Главное преимущество монорепозитория — единый источник правды для типов. Создадим пакет shared-types:

    // packages/shared-types/src/index.ts
    export interface User {
      id: string;
      email: string;
      name: string;
      role: 'admin' | 'user';
      createdAt: string;
    }
    
    export interface ApiResponse<T> {
      data: T;
      message: string;
      statusCode: number;
    }
    
    export interface PaginatedResponse<T> extends ApiResponse<T[]> {
      total: number;
      page: number;
      limit: number;
    }
    

    Теперь и фронтенд, и бэкенд используют одни и те же интерфейсы:

    // apps/api/src/users/users.controller.ts
    import { User, ApiResponse } from '@monorepo/shared-types';
    
    @Controller('users')
    export class UsersController {
      @Get(':id')
      async getUser(@Param('id') id: string): Promise<ApiResponse<User>> {
        const user = await this.usersService.findById(id);
        return { data: user, message: 'OK', statusCode: 200 };
      }
    }
    
    // apps/web/src/api/users.ts
    import { User, ApiResponse } from '@monorepo/shared-types';
    
    export async function fetchUser(id: string): Promise<User> {
      const res = await fetch(`/api/users/${id}`);
      const json: ApiResponse<User> = await res.json();
      return json.data;
    }
    

    Если кто-то изменит интерфейс User, TypeScript сразу покажет ошибки и во фронтенде, и в бэкенде. Никакой рассинхронизации.

    Локальная разработка: запуск фронта и бэка одной командой

    Одна из самых удобных возможностей Turborepo — запуск всех приложений одной командой:

    # Запустить все приложения в dev-режиме
    pnpm dev
    
    # Запустить только фронтенд
    pnpm dev --filter=web
    
    # Запустить фронтенд и его зависимости
    pnpm dev --filter=web...
    

    Флаг --filter позволяет работать с конкретным приложением. Три точки (...) означают: запусти пакет и все его зависимости. Это удобно, когда вы меняете общие типы и хотите видеть результат во фронтенде.

    Частые ошибки при организации монорепозитория

    Слишком много общих пакетов. Не выносите в отдельный пакет код, который использует только одно приложение. Начните с shared-types и добавляйте пакеты по мере необходимости.

    Циклические зависимости. Если пакет A зависит от B, а B от A, Turborepo не сможет определить порядок сборки. Решение — вынести общий код в третий пакет.

    Отсутствие outputs в turbo.json. Без указания outputs кэширование не работает. Всегда прописывайте, какие файлы создает задача: dist/** для библиотек, .next/** для Next.js.

    Тяжелый корневой package.json. Не устанавливайте зависимости приложений в корень. Каждое приложение должно объявлять свои зависимости в собственном package.json.

    Заключение

    Монорепозиторий на Turborepo — это практичный способ организовать фронтенд и бэкенд в одном репозитории без потери скорости сборки. Вы получаете единые типы, удобную локальную разработку и автоматическое кэширование. Начните с простой структуры — apps/ для приложений и packages/ для общего кода — и расширяйте по мере роста проекта. Turborepo не навязывает архитектуру, а ускоряет ту, которую вы выбрали сами.

    Иконка глаза7

    Комментарии

    0

    Постройте личный план изучения JavaScript с нуля - основы языка и практика для начинающих до уровня Middle — бесплатно!

    JavaScript с нуля - основы языка и практика для начинающих — часть карты развития Frontend, Backend, Mobile

    • step100+ шагов развития
    • lessons30 бесплатных лекций
    • lessons300 бонусных рублей на счет

    Бесплатные лекции

    Лучшие курсы по теме

    изображение курса

    Продвинутый JavaScript

    Антон Ларичев
    AI-тренажерыAI-тренажеры
    Практика в студииПрактика в студии
    Гарантия
    Бонусы
    иконка звёздочки рейтинга4.9
    3 999 ₽ 6 990 ₽
    Подробнее
    изображение курса

    TypeScript с нуля

    Антон Ларичев
    AI-тренажерыAI-тренажеры
    Практика в студииПрактика в студии
    Гарантия
    Бонусы
    иконка звёздочки рейтинга4.8
    3 999 ₽ 6 990 ₽
    Подробнее
    изображение курса

    React и Redux Toolkit

    Антон Ларичев
    AI-тренажерыAI-тренажеры
    Практика в студииПрактика в студии
    Гарантия
    Бонусы
    иконка звёздочки рейтинга4.8
    3 999 ₽ 6 990 ₽
    Подробнее

    Похожие статьи

    Картинка поста CQRS и Event Sourcing на практике: когда это оправдано, а когда — оверинжиниринг
    Иконка аватараАнтон
    Иконка календаря09 апреля 2026
    architecturetypescriptnodejsseniorИконка уровня senior

    CQRS и Event Sourcing на практике: когда это оправдано, а когда — оверинжиниринг

    CQRS и Event Sourcing — архитектурные паттерны для сложных доменов. Разбираем реальные примеры на TypeScript и NestJS, критерии выбора и типичные ошибки внедрения.

    Иконка чипа0
    Иконка глаза52
    Иконка комментариев0
    Картинка поста Дизайн-система в React с нуля: токены, компоненты и Storybook
    Иконка аватараАнтон
    Иконка календаря20 марта 2026
    reacttypescriptcssmiddleИконка уровня middle

    Дизайн-система в React с нуля: токены, компоненты и Storybook

    Разбираем, как построить дизайн-систему в React с нуля: от дизайн-токенов и CSS-переменных до переиспользуемых компонентов и документирования в Storybook.

    Иконка чипа0
    Иконка глаза173
    Иконка комментариев0
    Картинка поста Серверные компоненты в Next.js 15: когда SSR лучше CSR и наоборот
    Иконка аватараАнтон
    Иконка календаря19 марта 2026
    next.jsreacttypescriptmiddleИконка уровня middle

    Серверные компоненты в Next.js 15: когда SSR лучше CSR и наоборот

    Разбираем серверные и клиентские компоненты в Next.js 15: когда использовать SSR, а когда CSR. Практические примеры, паттерны композиции и типичные ошибки.

    Иконка чипа0
    Иконка глаза183
    Иконка комментариев0
    Иконка чипа0