Как правильно настроить env переменные Next.js на продакшене
Пошаговая инструкция с примерами для App Router и Pages Router
Переменные окружения — один из тех аспектов, где ошибка в конфигурации может стоить вам утечки API-ключей или падения продакшена. В Next.js есть свои особенности: часть переменных инлайнится в клиентский бандл на этапе сборки, часть доступна только на сервере, а поведение отличается между next dev, next build и next start. В этом гайде разберём, как настроить env-переменные так, чтобы всё работало предсказуемо на продакшене.
Требования и предварительная подготовка
Перед началом убедитесь, что у вас есть:
Проект на Next.js 13+ (App Router) или 12+ (Pages Router).
Node.js 18 или новее.
Доступ к панели управления хостингом (Vercel, Netlify, Docker, VPS).
Понимание, какие данные у вас секретные (ключи, токены), а какие публичные (URL API, ID аналитики).
Проверьте версию Next.js командой npx next --version. Если проект старый, обновите зависимости — синтаксис env-переменных в новых версиях стабильнее.
Шаг 1. Разберитесь с типами переменных в Next.js
Next.js делит переменные на две категории:
1. Публичные — с префиксом NEXT_PUBLIC_. Они инлайнятся в JavaScript-бандл на этапе сборки и доступны в браузере. Пример: NEXT_PUBLIC_API_URL. 2. Серверные — без префикса. Доступны только в серверном коде: в getServerSideProps, Route Handlers, Server Actions, API-роутах. Пример: DATABASE_URL, STRIPE_SECRET_KEY.
Важно: серверные переменные никогда не попадут в клиентский бандл, если вы не обратитесь к ним из клиентского компонента. Но если обратитесь — получите undefined или ошибку сборки.
Шаг 2. Создайте файлы .env для разных окружений
Next.js автоматически подхватывает файлы в таком порядке приоритета:
1. .env.$(NODE_ENV).local — например, .env.production.local. 2. .env.local — игнорируется в тестовом окружении (NODE_ENV=test). 3. .env.$(NODE_ENV) — например, .env.production. 4. .env — базовый файл для всех окружений.
Создайте в корне проекта:
.env
.env.local
.env.development
.env.productionВ .env храните безопасные значения по умолчанию. В .env.local — секреты для локальной разработки (этот файл должен быть в .gitignore). В .env.production — публичные переменные для продакшена, которые не являются секретами.
Шаг 3. Настройте .gitignore и защитите секреты
Убедитесь, что в .gitignore есть строки:
.env*.local
.env.production
.env.developmentНикогда не коммитьте файлы с реальными ключами. Если секрет уже попал в репозиторий — немедленно отзовите его и создайте новый. Git хранит историю, поэтому простое удаление файла не поможет.
Для командной работы создайте .env.example с перечнем переменных без значений:
DATABASE_URL=
NEXT_PUBLIC_API_URL=
STRIPE_SECRET_KEY=Этот файл коммитится и служит документацией.
Шаг 4. Используйте переменные в серверном коде
В App Router серверные переменные читаются напрямую через process.env:
// app/api/users/route.js
export async function GET() {
const res = await fetch(`${process.env.INTERNAL_API_URL}/users`, {
headers: { Authorization: `Bearer ${process.env.API_TOKEN}` }
});
return Response.json(await res.json());
}В Pages Router — внутри getServerSideProps или getStaticProps:
export async function getServerSideProps() {
const data = await fetch(process.env.INTERNAL_API_URL);
return { props: { data: await data.json() } };
}Серверные переменные не инлайнятся в бандл, поэтому их можно менять без пересборки (при использовании next start).
Шаг 5. Правильно работайте с NEXT_PUBLIC_ переменными
Публичные переменные встраиваются в код на этапе next build. Это значит:
Их нельзя изменить после сборки — нужно пересобирать приложение.
Они видны любому пользователю в исходниках страницы.
Их нельзя использовать для секретов.
Пример использования в клиентском компоненте:
'use client';
export default function Map() {
return <iframe src={`https://maps.example.com?key=${process.env.NEXT_PUBLIC_MAPS_KEY}`} />;
}Если переменная не начинается с NEXT_PUBLIC_, в браузере вы получите undefined.
Шаг 6. Настройте переменные на Vercel
Vercel — самый простой вариант. Перейдите в Project Settings → Environment Variables. Для каждой переменной укажите:
Key — имя переменной.
Value — значение.
Environments — Production, Preview, Development.
Особенности Vercel:
Переменные применяются при следующем деплое. После изменения нужно сделать Redeploy.
Для Preview-окружений можно задавать отдельные значения.
Секреты хранятся в зашифрованном виде.
Если вы используете Vercel CLI, можно добавить переменные командой vercel env add.
Шаг 7. Настройте переменные в Docker
При сборке Docker-образа Next.js нужно передать публичные переменные на этапе build, а серверные — на этапе run.
Пример Dockerfile:
FROM node:18-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
ARG NEXT_PUBLIC_API_URL
ENV NEXT_PUBLIC_API_URL=$NEXT_PUBLIC_API_URL
RUN npm run build
FROM node:18-alpine
WORKDIR /app
COPY --from=builder /app/.next ./.next
COPY --from=builder /app/public ./public
COPY --from=builder /app/package*.json ./
RUN npm ci --omit=dev
EXPOSE 3000
CMD ["npm", "start"]Сборка: docker build --build-arg NEXT_PUBLIC_API_URL=https://api.example.com -t myapp .
Запуск с серверными переменными: docker run -e DATABASE_URL=... -e STRIPE_SECRET_KEY=... -p 3000:3000 myapp.
Шаг 8. Настройте переменные на VPS с PM2
Если вы деплоите на собственный сервер, используйте файл .env.production прямо на сервере или передавайте переменные через PM2 ecosystem-файл:
// ecosystem.config.js
module.exports = {
apps: [{
name: 'next-app',
script: 'node_modules/next/dist/bin/next',
args: 'start',
env_production: {
NODE_ENV: 'production',
DATABASE_URL: 'postgres://...',
NEXT_PUBLIC_API_URL: 'https://api.example.com'
}
}]
};Запуск: pm2 start ecosystem.config.js --env production.
Помните: NEXT_PUBLIC_ переменные всё равно должны быть заданы на этапе сборки, иначе они не попадут в бандл.
Шаг 9. Проверьте переменные перед деплоем
Добавьте в проект скрипт валидации, который запускается перед сборкой. Например, с помощью библиотеки zod:
// env.mjs
import { z } from 'zod';
const schema = z.object({
DATABASE_URL: z.string().url(),
NEXT_PUBLIC_API_URL: z.string().url(),
STRIPE_SECRET_KEY: z.string().min(1)
});
schema.parse(process.env);Импортируйте этот файл в next.config.js, чтобы сборка падала при отсутствии переменной. Это спасёт от деплоя с undefined в критичных местах.
Шаг 10. Учитывайте особенности кэширования и ISR
При использовании Incremental Static Regeneration (ISR) страницы генерируются на сервере и кэшируются. Если страница использует серверные env-переменные, их значения фиксируются в момент генерации. При изменении переменной нужно перегенерировать страницы (через revalidate или on-demand revalidation).
Публичные переменные, использованные в ISR-страницах, инлайнятся в HTML и не обновятся без пересборки.
Шаг 11. Настройте разные значения для Preview и Production
На Vercel и Netlify можно задавать разные значения для Preview-деплоев. Это удобно, чтобы тестировать новые фичи на стейджинге, не трогая прод. Используйте отдельные базы данных, API-ключи и URL.
В Vercel: Environment Variables → выберите Preview → добавьте переменную с другим значением. При этом Production останется нетронутым.
Шаг 12. Проверьте, что секреты не утекли в клиент
После сборки выполните поиск по папке .next/static:
grep -r "SECRET_KEY" .next/staticЕсли что-то найдено — переменная попала в клиентский бандл. Причины: использование без префикса в клиентском компоненте, случайный импорт серверного модуля в клиент, или явная передача через props.
Также проверьте HTML-страницы: curl https://your-site.com | grep SECRET.
Типичные ошибки
1. Использование серверной переменной в клиентском компоненте. Next.js вернёт undefined, а не ошибку. Всегда проверяйте, где именно вы читаете process.env. 2. Забыли пересобрать после изменения NEXT_PUBLIC_. Публичные переменные фиксируются на этапе build. На Vercel нужен Redeploy. 3. Хранение секретов в .env.production в git. Даже в приватном репозитории это риск. Используйте переменные окружения хостинга. 4. Отсутствие валидации. Приложение падает в рантайме вместо ошибки на этапе сборки. 5. Путаница с NODE_ENV. Next.js сам выставляет production при next build, не переопределяйте его вручную без необходимости. 6. Использование .env.local на продакшене. Этот файл игнорируется в production-сборке, если не задан явно. 7. Динамические имена переменных. process.env[KEY_${id}] не работает — Next.js статически анализирует обращения.
FAQ
Можно ли менять серверные env-переменные без пересборки? Да, если вы используете next start или standalone-режим. Переменные читаются в рантайме. Но на Vercel серверные функции перезапускаются при деплое, поэтому изменение переменной требует Redeploy.
Почему NEXT_PUBLIC_ переменная undefined в браузере? Скорее всего, она не была задана на этапе сборки. Проверьте, что переменная есть в окружении билда, и пересоберите проект.
Как передать переменные в клиент, не используя NEXT_PUBLIC_? Можно передать их через props из серверного компонента или через API-роут. Но помните: всё, что попадает в клиент, видно пользователю.
Работает ли .env.local в Docker? Нет, если вы не скопируете его в образ. Лучше передавать переменные через --env-file или -e.
Что делать, если переменная нужна и на клиенте, и на сервере? Создайте две переменные: NEXT_PUBLIC_API_URL для клиента и INTERNAL_API_URL для сервера. Часто это разные адреса.
Как отладить, какие переменные видит приложение? Добавьте временный API-роут, который возвращает Object.keys(process.env), и проверьте его на продакшене. Не выводите значения — только имена.
Итог
Правильная настройка env-переменных в Next.js на продакшене сводится к трём принципам: чётко разделяйте публичные и серверные переменные, задавайте их в окружении хостинга, а не в git, и валидируйте перед сборкой. Помните, что NEXT_PUBLIC_ фиксируются на этапе build, а серверные читаются в рантайме. Следуя шагам выше, вы избежите утечек секретов и неожиданных undefined на проде.
Читайте также
Комментарии
Комментарии доступны только зарегистрированным пользователям. Войти
- Пока нет комментариев. Будьте первым.



