Переменные окружения

Переменные окружения (environment variables) — параметры конфигурации, передаваемые процессу через операционную систему, а не хранящиеся в коде: API ключи, URLs баз данных, режим работы приложения.

Зачем нужно

Хардкодить секреты (API keys, пароли БД) в коде — критическая ошибка: они попадают в git и становятся публичными. Переменные окружения отделяют конфигурацию от кода: одно приложение работает с разными настройками на dev/staging/production без изменения исходников.

Где используется

  • Хранение секретов: DATABASE_URL, JWT_SECRET, AWS_ACCESS_KEY
  • Режим работы: NODE_ENV=development/production/test
  • CI/CD пайплайны — секреты задаются в настройках GitHub Actions, Vercel, Railway
  • Docker и Kubernetes — переменные передаются в контейнер через env/secrets

Файл .env

# .env — локальная конфигурация (не коммитить!)
NODE_ENV=development
PORT=3000
DATABASE_URL=postgresql://user:password@localhost:5432/mydb
JWT_SECRET=your-super-secret-key-change-in-production
API_KEY=sk-1234567890abcdef

# .env.example — шаблон без реальных значений (коммитить)
NODE_ENV=development
PORT=3000
DATABASE_URL=postgresql://user:password@host:5432/dbname
JWT_SECRET=
API_KEY=
# .gitignore — обязательно
.env
.env.local
.env.*.local

Чтение в Node.js с dotenv

// Установка
// npm install dotenv

// index.js или server.js — первая строка
import 'dotenv/config';
// или
import dotenv from 'dotenv';
dotenv.config;

// Использование через process.env
const port = process.env.PORT ?? 3000;
const dbUrl = process.env.DATABASE_URL;
const jwtSecret = process.env.JWT_SECRET;

if (!jwtSecret) {
  throw new Error('JWT_SECRET не задан — приложение не запустится');
}

Валидация переменных окружения

// env.js — централизованная валидация при старте
const required = ['DATABASE_URL', 'JWT_SECRET', 'API_KEY'];

for (const key of required) {
  if (!process.env[key]) {
    throw new Error(`Обязательная переменная окружения ${key} не задана`);
  }
}

export const env = {
  port: Number(process.env.PORT) || 3000,
  nodeEnv: process.env.NODE_ENV || 'development',
  databaseUrl: process.env.DATABASE_URL,
  jwtSecret: process.env.JWT_SECRET,
  isDev: process.env.NODE_ENV !== 'production',
};

Несколько .env файлов

.env                 # дефолтные значения (можно коммитить без секретов)
.env.local           # локальные переопределения (не коммитить)
.env.development     # dev-окружение
.env.production      # production (не коммитить!)
.env.test            # для тестов

# dotenv загружает в порядке приоритета:
# .env.local > .env.[NODE_ENV] > .env

Vite и фронтенд

# Vite читает только переменные с префиксом VITE_
VITE_API_URL=https://api.example.com
VITE_APP_TITLE=My App

# НЕ ДЕЛАТЬ — секреты утекут в бандл браузера:
VITE_DATABASE_URL=...   # ОПАСНО
VITE_JWT_SECRET=...     # ОПАСНО
// Доступ в коде Vite
const apiUrl = import.meta.env.VITE_API_URL;
const isDev = import.meta.env.DEV;
const isProd = import.meta.env.PROD;

Частые ошибки

  • Коммит .env с реальными секретами в git — секрет компрометирован навсегда, нужна немедленная ротация ключей
  • Нет .env.example — новый разработчик не знает, какие переменные нужны
  • Нет валидации при старте — приложение запускается без секрета и падает в runtime с непонятной ошибкой
  • VITE_SECRET_KEY на фронтенде — все переменные VITE_ попадают в JS-бандл и видны пользователям
  • process.env.PORT как число без приведения типа — process.env всегда возвращает строку

Связанные темы

Ресурсы