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

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

  • Курсы
    • FrontendИконка стрелки
    • AI разработкаИконка стрелки
    • BackendИконка стрелки
    • DevOpsИконка стрелки
    • MobileИконка стрелки
    • ТестированиеИконка стрелки
    • Soft-skillsИконка стрелки
    • ДизайнИконка стрелки
    Иконка слояПерейти в каталог курсов
  • Бесплатно
    • Курсы
    • JavaScript Основы разработкиPython Основы PythonCSS CSS FlexboxКарта развитияВопросы для собеседований
    • База знанийИконка стрелки
    • Новостные рассылкиИконка стрелки
  • PurpleSchool — курсы программирования онлайн
    • AI для кодаНовое
    • Сообщество
    • PurpleПлюс
    • AI Собеседование
    • 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 не навязывает архитектуру, а ускоряет ту, которую вы выбрали сами.

    Иконка глаза1 507

    Комментарии

    0

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

    Основы разработки — часть карты развития Frontend, Backend, Mobile

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

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

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

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

    Основы Git

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

    HTML и CSS

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

    CSS Flexbox

    Антон Ларичев
    Гарантия
    Бонусы
    иконка звёздочки рейтинга4.9
    бесплатно
    Подробнее

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

    Картинка поста Настройка очередей с retray на laravel и Foton сравнение
    Иконка аватараКонстантин
    Иконка календаря08 октября 2026
    очередиlaravelretray+ 3middleИконка уровня middle

    Настройка очередей с retray на laravel и Foton сравнение

    Создание очередей с retray на примерах фреймворков Laravel и Foton

    Иконка чипа0
    Иконка глаза36
    Иконка комментариев0
    Иконка аватараАнтон
    Иконка календаря08 октября 2026
    AI-инструментыopenaiapi+ 2middleИконка уровня middle

    OpenCode Zen или свой API-ключ: что выгоднее в России

    OpenCode Zen — это шлюз с отобранными командой OpenCode моделями, где вы платите по факту за токены. Свой API-ключ — это когда вы подключаете к OpenCode отдельного провайдера и платите ему. Для разработчика из России выбор решается не ценой за токен, а способом оплаты: в Zen нужно привязать биллинг и платить в долларах, а ключ российского прокси оплачивается рублёвой картой.

    Иконка чипа0
    Иконка глаза78
    Иконка комментариев0
    Картинка поста Работа с DI-контейнером на Framework Foton
    Иконка аватараКонстантин
    Иконка календаря07 октября 2026
    di-контейнерframework FotonFotonmiddleИконка уровня middle

    Работа с DI-контейнером на Framework Foton

    Что такое DI-контейнер и как с ним работать с примерами для самых маленьких на примере системы сборщика и внедрения зависимостей с автоматическим разрешением аргументов конструктора через рефлексию на Framework Foton

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