sadrix logoSadriX
Минцифры готовит обязательную регистрацию IMEI смартфонов, купленных за границей
Гайды

Как правильно настроить env переменные Next.js на продакшене

Пошаговая инструкция с примерами для App Router и Pages Router

08 791 просмотров6 мин
0
Поделиться:TelegramVK

Переменные окружения — один из тех аспектов, где ошибка в конфигурации может стоить вам утечки 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 на проде.

Читайте также

Комментарии

Комментарии доступны только зарегистрированным пользователям. Войти

  • Пока нет комментариев. Будьте первым.