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

Переменные окружения — способ хранения конфигурации и секретов (паролей, API-ключей) вне кода: .env-файл содержит их локально, в продакшне задаются через сервер или CI/CD.

Зачем нужно

Хардкодить пароли и ключи в коде опасно: они попадают в Git и становятся публичными. .env-файл хранит конфигурацию отдельно и добавляется в .gitignore. Разные среды (development, staging, production) имеют разные значения одних и тех же переменных — это стандартный паттерн 12-factor app.

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

  • Строки подключения к БД (DATABASE_URL)
  • API-ключи внешних сервисов (Stripe, Twilio, SendGrid)
  • JWT secrets, session secrets
  • Параметры конфигурации среды (NODE_ENV, PORT, LOG_LEVEL)

Основной контент

Файл .env

# .env — только для локальной разработки, в .gitignore!
NODE_ENV=development
PORT=3000

DATABASE_URL=postgres://user:password@localhost:5432/mydb
REDIS_URL=redis://localhost:6379

JWT_SECRET=local-dev-secret-not-for-production
STRIPE_SECRET_KEY=sk_test_...
SENDGRID_API_KEY=SG.xxx...

# Опциональные с дефолтами
LOG_LEVEL=debug
MAX_CONNECTIONS=10

.env.example — шаблон для команды

# .env.example — КОММИТИТСЯ в Git (без реальных значений)
NODE_ENV=
PORT=3000

DATABASE_URL=postgres://user:password@localhost:5432/mydb
REDIS_URL=redis://localhost:6379

JWT_SECRET=
STRIPE_SECRET_KEY=
SENDGRID_API_KEY=

.gitignore

.env
.env.local
.env.*.local
# НЕ игнорировать:
# .env.example — шаблон для команды

Node.js: доступ к переменным

// Нативно — Node.js 20.6+ (без dotenv!)
// запуск: node --env-file=.env server.js

// Или через dotenv
// npm install dotenv
require('dotenv').config;

// Доступ
const port = process.env.PORT || 3000;
const dbUrl = process.env.DATABASE_URL;

if (!dbUrl) {
  throw new Error('DATABASE_URL is required');
}

Валидация переменных при старте (Zod)

const { z } = require('zod');

const envSchema = z.object({
  NODE_ENV: z.enum(['development', 'staging', 'production']),
  PORT: z.coerce.number.default(3000),
  DATABASE_URL: z.string.url,
  JWT_SECRET: z.string.min(32),
});

const env = envSchema.parse(process.env);
// Если переменная отсутствует — выбросит ошибку при старте, а не при первом использовании
module.exports = { env };

В продакшне: GitHub Actions Secrets

# .github/workflows/deploy.yml
- name: Deploy
  run: npm run deploy
  env:
    DATABASE_URL: ${{ secrets.DATABASE_URL }}
    JWT_SECRET: ${{ secrets.JWT_SECRET }}

Docker / docker-compose

# docker-compose.yml
services:
  api:
    env_file:
      - .env          # загрузить из файла
    environment:
      NODE_ENV: production   # или переопределить конкретные
# Передать при запуске контейнера
docker run -e NODE_ENV=production --env-file .env myapp:latest

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

  • Закоммитить .env с реальными секретами — сразу добавить в .gitignore и ротировать ключи
  • Не иметь .env.example — новый разработчик не знает какие переменные нужны
  • Читать process.env в разных местах кода без валидации — лучше парсить один раз при старте
  • Одинаковые JWT_SECRET в development и production — секреты должны отличаться по средам

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

Ресурсы