Документы · Инструкция
pnpm deploy: как собрать production-пакет из workspace
`pnpm deploy` полезен, когда из monorepo нужно выпустить одно приложение как отдельный переносимый production-пакет.
Короткий ответ
`pnpm deploy` собирает из выбранного workspace-пакета переносимую директорию для запуска вне monorepo. Для production-сборки обычно используют `pnpm --filter=<package> --prod deploy <target>`: команда копирует файлы пакета и формирует изолированный `node_modules` с нужными зависимостями.
Когда pnpm deploy полезнее обычного копирования workspace
В monorepo приложение часто зависит от локальных workspace-пакетов, общего lockfile и структуры, которой нет на production-сервере. Если просто скопировать папку приложения, внутри могут остаться ссылки на соседние директории, а установка зависимостей потребует всего репозитория. `pnpm deploy` предназначен для противоположного результата: создать автономную директорию выбранного пакета, которую можно перенести на другую машину. Официальная документация pnpm описывает deploy как способ получить portable package с изолированным `node_modules`. Это удобно для Docker multi-stage builds, архивов релиза и серверов, куда не хочется отправлять исходники всего monorepo.
Важно: Deploy не заменяет ваш build. Если приложение нужно сначала скомпилировать в `dist`, сделайте build до упаковки и убедитесь, что `dist` входит в набор копируемых файлов.
Базовый production deploy выбранного workspace
- Сначала соберите целевой пакет и его необходимые workspace-зависимости обычной командой вашего проекта. Например, выполните общий build или фильтрованный build до стадии deploy.
- Из корня workspace вызовите `pnpm --filter=<имя-пакета> --prod deploy <каталог>`. Фильтр должен однозначно выбирать именно приложение, которое вы выпускаете.
- Проверьте содержимое target-директории: там должны быть runtime-файлы приложения и `node_modules`, а не случайные тестовые фикстуры, локальные секреты или кэш.
- Запустите приложение непосредственно из deploy-каталога в окружении, максимально похожем на production. Так вы заметите скрытую зависимость от файлов monorepo до контейнеризации.
- Если собираете Docker image, копируйте в финальный stage только результат deploy и необходимые системные файлы. Это уменьшает контекст финального слоя и отделяет build-time инструменты.
- Зафиксируйте команду в CI, а не собирайте production-папку вручную. Повторяемость важнее локально удачной разовой упаковки.
Совет: Перед первым релизом временно переименуйте или сделайте недоступным корень monorepo и запустите deploy-папку отдельно. Так проще найти случайные относительные импорты наружу.
Какие файлы попадут в deploy и почему это надо проверять
pnpm использует правила упаковки пакета, чтобы решить, какие файлы переносить. Согласно текущей документации deploy, при наличии поля `files` в `package.json` оно определяет набор файлов; в других случаях учитываются правила `.npmignore`, а при его отсутствии — `.gitignore`. Поэтому файл, который отлично существует в рабочем дереве, может неожиданно исчезнуть из deploy-папки. Типичный пример — сгенерированный `dist`, случайно исключённый `.gitignore`, или шаблон конфигурации, который приложение читает во время запуска. Обратная проблема тоже возможна: в пакет попадают тесты, карты исходников или локальные файлы, которые production не нужны. Рассматривайте deploy как реальную упаковку артефакта и проверяйте manifest файлов в CI.
Deploy, pack и обычный install решают разные задачи
- pnpm deploy. Готовая переносимая директория пакета + runtime dependencies. Production image или серверный артефакт
- pnpm pack. npm-compatible tarball пакета. Публикация/проверка содержимого библиотеки
- pnpm install --prod. Production dependencies в текущем проекте. Установка на месте при наличии нужного package context
- Копирование папки. Только выбранные вами файлы. Простой standalone-проект без workspace-связей
Предупреждение: Не используйте `--prod` как способ «удалить всё лишнее» из исходников: он относится к набору зависимостей, а состав файлов контролируется правилами упаковки.
Локальные workspace-зависимости и изоляция node_modules
Главная ценность deploy проявляется, когда приложение импортирует собственные пакеты monorepo. В рабочем workspace pnpm может связывать их через свою структуру ссылок, но production-артефакт должен быть самодостаточным. deploy формирует результат так, чтобы выбранный пакет можно было запускать вне исходного workspace. Это всё равно не освобождает от проверки runtime: native-модули должны соответствовать платформе контейнера, optional dependencies могут зависеть от OS/CPU, а переменные окружения не становятся частью артефакта автоматически. Если build выполняется на одной платформе, а запуск на другой, особенно внимательно тестируйте зависимости с нативными бинарниками.
Как встроить pnpm deploy в Docker multi-stage build
Рациональная схема состоит из build stage и runtime stage. В первом устанавливаются зависимости по lockfile, компилируются нужные workspace-пакеты и выполняется `pnpm deploy` в отдельный каталог. Во второй stage переносится только этот каталог, после чего задаются рабочая директория, непривилегированный пользователь и команда запуска. Такая конструкция не гарантирует маленький image автоматически: если package rules включают исходники и большие ассеты, они тоже попадут внутрь. Поэтому измеряйте размер слоёв и просматривайте содержимое target. Также не копируйте токены registry или `.npmrc` с секретами в финальный stage — они нужны только на этапе установки.
Что проверить перед выпуском deploy-артефакта
- Целевой `--filter` выбирает ровно один нужный workspace-пакет.
- Приложение собрано до deploy, а сгенерированные файлы реально входят в target.
- Production-зависимости присутствуют, devDependencies не нужны во время запуска.
- В deploy нет `.env`, токенов, registry credentials и других секретов.
- Приложение запускается из target без доступа к родительскому monorepo.
- Версия Node.js и платформа runtime совместимы с собранными native dependencies.
- CI использует lockfile и повторяемую команду, а итоговый каталог можно архивировать или копировать в финальный image.
Типичные причины, почему deploy запускается локально, но падает в production
Первый класс ошибок — отсутствующий файл: он был в рабочем дереве, но исключён правилами `files`/ignore. Второй — скрытая devDependency, которую код использует во время runtime, хотя она объявлена как development-only и пропадает при `--prod`. Третий — путь, рассчитанный относительно корня monorepo, например чтение `././config.json`. Четвёртый — платформенная разница в нативном модуле. Чтобы не отлавливать это после релиза, запускайте smoke-test именно из deploy-папки, а не из исходного workspace. Если тест проходит в чистом runtime-контейнере, вероятность инфраструктурного сюрприза резко ниже.
Что изменилось в pnpm deploy в актуальной ветке 12.x
У текущей документации pnpm 12.x есть важный нюанс для старых инструкций из блогов: начиная с pnpm 12.2.0 команда `deploy` больше не требует обязательного `injectWorkspacePackages`. Для linked workspace dependency pnpm формирует отдельный deploy lockfile и переписывает связь в подходящую локальную зависимость внутри артефакта. Если в графе один peer dependency разрешается несколькими версиями и выбор неоднозначен, deploy может завершиться ошибкой `ERR_PNPM_DEPLOY_AMBIGUOUS_PEER`; тогда нужно устранить неоднозначность, например осознанным `overrides`, либо использовать поведение, предусмотренное документацией. Флаг `--legacy` и настройка `forceLegacyDeploy` оставлены для старой реализации, поэтому не копируйте их в новый pipeline без причины. Для стабильного CI фиксируйте версию pnpm и тестируйте deploy-каталог как самостоятельный артефакт после обновления package manager.
Что учитывать
pnpm использует правила упаковки пакета, чтобы решить, какие файлы переносить. Согласно текущей документации deploy, при наличии поля `files` в `package.json` оно определяет набор файлов; в других случаях учитываются правила `.npmignore`, а при его отсутствии — `.gitignore`. Поэтому файл, который отлично существует в рабочем дереве, может неожиданно исчезнуть из deploy-папки. Типичный пример — сгенерированный `dist`, случайно исключённый `.gitignore`, или шаблон конфигурации, который приложение…
Источники и проверка
Фактическая часть сверена по первичным источникам (в т.ч. pnpm deploy). Пример и формулировки — редакция N1RO на 2026-09-21.