Полное руководство по CI/CD для Next.js в GitLab: от базовой настройки до продакшн-пайплайна
30 марта 2026 г.
Настройка CI/CD для Next.js в GitLab — это не просто добавление файла .gitlab-ci.yml. Чтобы пайплайн работал быстро, надёжно и покрывал все сценарии (от разработки до продакшена), нужно учитывать особенности сборки Next.js, кэширования, типов деплоя и безопасности. В этом руководстве я детально разберу каждый этап, предоставлю готовые конфигурации с комментариями и объясню, как адаптировать их под ваши задачи.
Особенности Next.js в CI/CD: что нужно знать
Next.js имеет гибридную архитектуру, что накладывает особенности на сборку и деплой:
- SSG (Static Site Generation) — страницы генерируются на этапе
next build. В CI это означает, что все данные, необходимые для генерации, должны быть доступны в окружении сборки (переменные окружения, API). - SSR (Server-Side Rendering) — код выполняется на сервере. При деплое нужно убедиться, что Node.js окружение на целевом сервере соответствует требованиям.
- ISR (Incremental Static Regeneration) — требует, чтобы сервер (или функция) могла перестраивать страницы. Это влияет на выбор платформы деплоя.
- Image Optimization — может требовать установки дополнительных зависимостей (
sharp) и наличия файловой системы для кэша. - Артефакты сборки — папка
.nextсодержит как статику, так и серверный код. Важно правильно передавать её на этап деплоя.
Структура .gitlab-ci.yml: разбор stages и переменных
Файл .gitlab-ci.yml состоит из глобальных настроек, переменных, кэшей и списка джобов, сгруппированных по этапам (stages). Рассмотрим базовый каркас с комментариями:
# Определяем порядок выполнения этапов
stages:
- install # Установка зависимостей
- test # Линтинг и тесты
- build # Сборка приложения
- deploy_staging # Деплой на стейджинг
- deploy_prod # Деплой на продакшен
# Глобальные переменные, доступные во всех джобах
variables:
NODE_VERSION: "20" # Версия Node.js
NPM_CACHE: "$CI_PROJECT_DIR/.npm" # Путь для кэша npm
# Префикс для кэшей, чтобы различать ветки
CACHE_KEY: "${CI_COMMIT_REF_SLUG}-${CI_JOB_NAME}"
# Кэширование на уровне проекта
cache:
key: "${CI_COMMIT_REF_SLUG}" # Ключ кэша зависит от ветки
paths:
- .npm/ # Кэш npm
- node_modules/ # Сами зависимости
policy: pull-push # По умолчанию загружаем и сохраняем
# Дефолтные настройки для всех джобов (можно переопределить)
default:
image: node:${NODE_VERSION} # Базовый образ для всех джобов
before_script:
- npm config set cache $NPM_CACHE # Указываем npm путь для кэша
- npm ci --cache $NPM_CACHE --prefer-offline || true # Пытаемся восстановить кэш
interruptible: true # Прерывать старые пайплайны при новом пуше
Этап 1: Установка зависимостей с кэшированием
Первый этап — установка зависимостей. Здесь мы используем npm ci для точного воспроизведения package-lock.json. Важно настроить кэш, чтобы ускорить последующие джобы.
install_dependencies:
stage: install
script:
- npm ci --cache $NPM_CACHE --prefer-offline
artifacts: # Сохраняем node_modules как артефакт
paths:
- node_modules/
expire_in: 1 hour # Храним недолго, чтобы не раздувать хранилище
cache:
key: "${CI_COMMIT_REF_SLUG}-node-modules"
paths:
- node_modules/
policy: pull-push # Загружаем и сохраняем кэш
Почему npm ci вместо npm install? npm ci удаляет node_modules и устанавливает зависимости строго по lock-файлу, что гарантирует воспроизводимость сборки. Это идеально для CI.
Этап 2: Тестирование — линтер и unit-тесты
На этом этапе мы проверяем качество кода. Чтобы ускорить выполнение, используем артефакты от предыдущего этапа.
run_lint:
stage: test
script:
- npm run lint
dependencies:
- install_dependencies # Используем node_modules из предыдущего этапа
cache: # Не сохраняем кэш для этого джоба
policy: pull
run_tests:
stage: test
script:
- npm run test -- --coverage # Запускаем тесты с покрытием
artifacts:
paths:
- coverage/ # Сохраняем отчет о покрытии
reports:
coverage_report:
coverage_format: cobertura
path: coverage/cobertura-coverage.xml
expire_in: 1 week
dependencies:
- install_dependencies
cache:
policy: pull
Если вы используете TypeScript, добавьте проверку типов отдельной командой: npm run type-check. Для ускорения можно запускать тесты параллельно, используя parallel: matrix в GitLab CI.
Этап 3: Сборка Next.js — SSG, SSR и артефакты
Сборка Next.js требует наличия всех переменных окружения, которые используются во время next build (например, для SSG или API-ключей). Также важно сохранить артефакты для деплоя.
build_nextjs:
stage: build
script:
# Переменные окружения для сборки (можно передать через GitLab CI/CD variables)
- export NEXT_PUBLIC_API_URL=$NEXT_PUBLIC_API_URL
- export NEXT_PUBLIC_APP_ENV=$CI_ENVIRONMENT_NAME
- npm run build
artifacts:
paths:
- .next/ # Основные артефакты сборки
- public/ # Публичные файлы
- node_modules/ # Нужны для запуска сервера
- package.json
- package-lock.json
expire_in: 1 week
reports:
dotenv: build.env # Сохраняем переменные для следующих этапов
dependencies:
- install_dependencies
cache:
key: "${CI_COMMIT_REF_SLUG}-build"
paths:
- .next/cache/ # Кэш Next.js для ускорения пересборок
policy: pull-push
after_script:
# Сохраняем используемые переменные в файл для артефакта
- echo "NEXT_PUBLIC_API_URL=$NEXT_PUBLIC_API_URL" > build.env
- echo "NEXT_PUBLIC_APP_ENV=$CI_ENVIRONMENT_NAME" >> build.env
Важно: папка .next/cache/ значительно ускоряет последующие сборки. Добавьте её в кэш. Также обратите внимание, что для SSR-деплоя нужны node_modules, package.json и lock-файл.
Этап 4: Деплой — стратегии для разных сред
Выбор стратегии деплоя зависит от того, где будет работать ваше приложение. Рассмотрим три популярных варианта с полными примерами.
Деплой на Vercel через API-токен
Vercel — нативная платформа для Next.js. Для автоматизации используем Vercel CLI и токен.
deploy_vercel_staging:
stage: deploy_staging
image: node:${NODE_VERSION}
script:
- npm install -g vercel
# Деплой на стейджинг с явным указанием окружения
- vercel --token ${VERCEL_TOKEN} --scope ${VERCEL_TEAM} --prod --confirm --environment preview
environment:
name: staging/vercel
url: https://${CI_COMMIT_REF_SLUG}.my-app.vercel.app
only:
- develop
- merge_requests
dependencies:
- build_nextjs
# Продакшен деплой на Vercel
deploy_vercel_prod:
stage: deploy_prod
image: node:${NODE_VERSION}
script:
- npm install -g vercel
- vercel --token ${VERCEL_TOKEN} --scope ${VERCEL_TEAM} --prod --confirm
environment:
name: production/vercel
url: https://my-app.com
only:
- main
dependencies:
- build_nextjs
when: manual # Ручной запуск для продакшена
Переменные окружения: VERCEL_TOKEN (токен аккаунта), VERCEL_TEAM (ID команды, если используется).
Деплой на VPS через SSH и rsync
Для деплоя на собственный сервер используем rsync для передачи файлов и перезапуска процесса через systemd или PM2.
deploy_vps:
stage: deploy_prod
image: alpine:latest
before_script:
- apk add --no-cache rsync openssh-client bash
- mkdir -p ~/.ssh
- echo "$SSH_PRIVATE_KEY" > ~/.ssh/id_rsa
- chmod 600 ~/.ssh/id_rsa
- eval $(ssh-agent -s)
- ssh-add ~/.ssh/id_rsa
- echo "$SSH_KNOWN_HOSTS" > ~/.ssh/known_hosts
script:
# Синхронизируем артефакты сборки
- rsync -avz --delete --exclude '.git' --exclude '.env' .next/ $SSH_USER@$SSH_HOST:/var/www/my-app/.next/
- rsync -avz --delete public/ $SSH_USER@$SSH_HOST:/var/www/my-app/public/
- rsync -avz node_modules/ $SSH_USER@$SSH_HOST:/var/www/my-app/node_modules/
- rsync -avz package.json package-lock.json $SSH_USER@$SSH_HOST:/var/www/my-app/
# Запускаем скрипт обновления на сервере
- ssh $SSH_USER@$SSH_HOST "cd /var/www/my-app && export NODE_ENV=production && pm2 reload ecosystem.config.js || pm2 start ecosystem.config.js"
environment:
name: production/vps
url: https://my-app.com
only:
- main
dependencies:
- build_nextjs
Важно: на сервере должен быть установлен PM2 (npm install -g pm2) и создан файл ecosystem.config.js для управления процессом Next.js.
Деплой через Docker в GitLab Registry
Современный подход — упаковка приложения в Docker-образ. GitLab предоставляет встроенный Container Registry.
docker_build:
stage: build
image: docker:latest
services:
- docker:dind
variables:
DOCKER_TLS_CERTDIR: "/certs"
before_script:
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
script:
- docker build --build-arg NEXT_PUBLIC_API_URL=$NEXT_PUBLIC_API_URL -t $CI_REGISTRY_IMAGE:${CI_COMMIT_SHORT_SHA} .
- docker push $CI_REGISTRY_IMAGE:${CI_COMMIT_SHORT_SHA}
- docker tag $CI_REGISTRY_IMAGE:${CI_COMMIT_SHORT_SHA} $CI_REGISTRY_IMAGE:latest
- docker push $CI_REGISTRY_IMAGE:latest
only:
- main
- develop
# Пример деплоя Docker-образа на сервер
deploy_docker:
stage: deploy_prod
image: alpine:latest
before_script:
- apk add --no-cache openssh-client
- mkdir -p ~/.ssh
- echo "$SSH_PRIVATE_KEY" > ~/.ssh/id_rsa
- chmod 600 ~/.ssh/id_rsa
script:
- ssh $SSH_USER@$SSH_HOST "docker pull $CI_REGISTRY_IMAGE:${CI_COMMIT_SHORT_SHA} && docker stop my-app || true && docker rm my-app || true && docker run -d --name my-app -p 3000:3000 $CI_REGISTRY_IMAGE:${CI_COMMIT_SHORT_SHA}"
only:
- main
dependencies: []
Для Docker-подхода в репозитории нужен Dockerfile с оптимизированной многоступенчатой сборкой Next.js.
Переменные окружения в GitLab: защита секретов
Все чувствительные данные (токены, ключи API, пароли) должны храниться в Protected Variables GitLab:
- Перейдите в Settings → CI/CD → Variables.
- Добавьте переменную, укажите ключ и значение.
- Включите Protected (доступна только для защищённых веток, например, main) и Masked (скрывает значение в логах).
- Для разных окружений можно использовать Environment scopes (например,
production/*).
Пример использования в пайплайне: $VERCEL_TOKEN или $SSH_PRIVATE_KEY. Никогда не встраивайте секреты в код.
Оптимизация пайплайна: кэши, параллелизм, условные запуски
Чтобы пайплайн выполнялся быстро, используйте следующие приёмы:
- Кэширование — кэшируйте
node_modulesи.next/cache. Ключ кэша должен меняться при измененииpackage-lock.json(используйтеkey: files: package-lock.json). - Параллельное выполнение — этапы
testможно запускать параллельно, если они не зависят друг от друга. - Условные запуски — используйте
only: changes, чтобы не запускать тяжёлые этапы при изменении документации:
only:
changes:
- "src/**/*"
- "package.json"
- "package-lock.json"
- Limit resources — для self-hosted раннеров укажите тэги с нужными ресурсами.
Обработка ошибок и уведомления
При сбое пайплайна важно получать уведомления. GitLab позволяет настроить:
- Slack-интеграцию через вебхук в настройках проекта.
- Telegram-бота через кастомный скрипт в
after_script. - Email-уведомления для членов команды.
Добавьте в критичные джобы (деплой) ручной подтверждение с помощью when: manual и allow_failure: false.
Полный пример .gitlab-ci.yml для production
Ниже представлен полный файл конфигурации, объединяющий все описанные элементы с комментариями:
stages:
- install
- test
- build
- deploy_staging
- deploy_prod
variables:
NODE_VERSION: "20"
NPM_CACHE: "$CI_PROJECT_DIR/.npm"
cache:
key: "${CI_COMMIT_REF_SLUG}"
paths:
- .npm/
- node_modules/
policy: pull-push
default:
image: node:${NODE_VERSION}
before_script:
- npm config set cache $NPM_CACHE
- npm ci --cache $NPM_CACHE --prefer-offline || true
interruptible: true
install_dependencies:
stage: install
script:
- npm ci --cache $NPM_CACHE --prefer-offline
artifacts:
paths:
- node_modules/
expire_in: 1 hour
run_lint:
stage: test
script:
- npm run lint
dependencies:
- install_dependencies
cache:
policy: pull
run_tests:
stage: test
script:
- npm run test -- --coverage
artifacts:
paths:
- coverage/
reports:
coverage_report:
coverage_format: cobertura
path: coverage/cobertura-coverage.xml
dependencies:
- install_dependencies
cache:
policy: pull
build_nextjs:
stage: build
script:
- export NEXT_PUBLIC_API_URL=$NEXT_PUBLIC_API_URL
- npm run build
artifacts:
paths:
- .next/
- public/
- node_modules/
- package.json
- package-lock.json
expire_in: 1 week
dependencies:
- install_dependencies
cache:
key: "${CI_COMMIT_REF_SLUG}-build"
paths:
- .next/cache/
policy: pull-push
deploy_vercel_staging:
stage: deploy_staging
image: node:${NODE_VERSION}
script:
- npm install -g vercel
- vercel --token ${VERCEL_TOKEN} --scope ${VERCEL_TEAM} --prod --confirm --environment preview
environment:
name: staging/vercel
url: https://${CI_COMMIT_REF_SLUG}.my-app.vercel.app
only:
- develop
- merge_requests
dependencies:
- build_nextjs
deploy_vercel_prod:
stage: deploy_prod
image: node:${NODE_VERSION}
script:
- npm install -g vercel
- vercel --token ${VERCEL_TOKEN} --scope ${VERCEL_TEAM} --prod --confirm
environment:
name: production/vercel
url: https://my-app.com
only:
- main
dependencies:
- build_nextjs
when: manual
Заключение
Мы детально разобрали настройку CI/CD для Next.js в GitLab — от базовых этапов до сложных стратегий деплоя с учётом особенностей фреймворка. Используя приведённые примеры и оптимизации, вы сможете создать надёжный и быстрый пайплайн, который автоматизирует выпуск вашего приложения. Не забывайте регулярно обновлять версии Node.js, проверять безопасность переменных и адаптировать конфигурацию под изменения в проекте.
Если вы ищете надёжную инфраструктуру для размещения вашего Next.js приложения, обратите внимание на облачные решения Timeweb Cloud или классический хостинг Timeweb, которые поддерживают Node.js и предоставляют удобные инструменты для CI/CD.
Что почитать дальше
Дополнительные материалы из архива, которые могут быть полезны после этой статьи.
Production-ready запуск React-приложения: от сборки до деплоя
Полное руководство по подготовке React-приложения к production: оптимизация сборки, настройка сервера, управление конфи…
Читать далее
Работа с Docker на хостинге: от локального контейнера до продакшен-сервера
Полное руководство по запуску Docker на VPS: установка, настройка volume'ов, работа с Docker Compose, обеспечение безоп…
Читать далее
Production-деплой Next.js на VPS: пошаговое руководство
Научитесь деплоить Next.js приложение на VPS как профессионал: от настройки сервера и PM2 до запуска через Docker, наст…
Читать далее