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

dotenv — библиотека для загрузки переменных окружения из файла .env в process.env, позволяющая хранить конфигурацию (ключи API, строки подключения к БД) вне кода и отдельно для каждого окружения.

Зачем нужно

Хардкодинг секретов (паролей, API-ключей) в коде — угроза безопасности: они попадают в git-историю и видны всей команде. Переменные окружения разделяют конфигурацию и код: разные значения в development, staging, production при одном и том же коде. .env файл добавляется в .gitignore.

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

  • Строки подключения к БД (DATABASE_URL)
  • API-ключи и секреты (JWT_SECRET, STRIPE_KEY, SMTP_PASSWORD)
  • Настройки порта и окружения (PORT, NODE_ENV)
  • Feature-флаги (FEATURE_NEW_UI=true)

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

Установка и использование

npm install dotenv
# .env (добавить в .gitignore!)
NODE_ENV=development
PORT=3000
DATABASE_URL=postgresql://user:password@localhost:5432/myapp
JWT_SECRET=super-secret-key-min-32-chars
REDIS_URL=redis://localhost:6379
SMTP_USER=noreply@example.com
SMTP_PASS=email-password
// app.js — ПЕРВОЙ строкой до всех импортов
require('dotenv').config;

// Теперь доступно через process.env
const port = process.env.PORT || 3000;
const dbUrl = process.env.DATABASE_URL;
const jwtSecret = process.env.JWT_SECRET;

console.log(`Server running in ${process.env.NODE_ENV} mode on port ${port}`);

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

.env                  # базовые значения (можно коммитить без секретов)
.env.development      # overrides для dev
.env.production       # overrides для production
.env.test             # для тестов
.env.local            # локальные overrides (не коммитить)
// Загрузить нужный файл
require('dotenv').config({ path: `.env.${process.env.NODE_ENV}` });

Конфигурационный модуль (рекомендуемый паттерн)

// config/index.js — единая точка конфигурации
require('dotenv').config;

function required(name) {
  const value = process.env[name];
  if (!value) throw new Error(`Missing required environment variable: ${name}`);
  return value;
}

module.exports = {
  env: process.env.NODE_ENV || 'development',
  port: parseInt(process.env.PORT, 10) || 3000,

  db: {
    url: required('DATABASE_URL'),
    maxConnections: parseInt(process.env.DB_MAX_CONNECTIONS, 10) || 10,
  },

  jwt: {
    secret: required('JWT_SECRET'),
    expiresIn: process.env.JWT_EXPIRES_IN || '7d',
  },

  redis: {
    url: process.env.REDIS_URL || 'redis://localhost:6379',
  },

  isProduction: process.env.NODE_ENV === 'production',
  isDevelopment: process.env.NODE_ENV === 'development',
};
// Использование в других файлах
const config = require('../config');

const pool = new Pool({ connectionString: config.db.url });
const token = jwt.sign(payload, config.jwt.secret, { expiresIn: config.jwt.expiresIn });

.env.example — документация переменных

# .env.example — этот файл КОММИТЯТ в git
# Скопируй в .env и заполни реальными значениями
NODE_ENV=development
PORT=3000
DATABASE_URL=postgresql://user:password@localhost:5432/myapp
JWT_SECRET=            # минимум 32 символа, генерировать через: openssl rand -base64 32
REDIS_URL=redis://localhost:6379
# Новый разработчик:
cp .env.example .env
# Заполнить .env, затем запустить приложение

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

  • Коммитить .env в git — добавить .env в .gitignore немедленно после создания проекта
  • Не вызывать dotenv.config первым — если модуль с process.env.DB_URL импортируется раньше dotenv, значение будет undefined
  • Не валидировать обязательные переменные — приложение запустится без DATABASE_URL и упадёт в неочевидном месте; использовать функцию required
  • Хранить .env в Docker образе — переменные передавать через -e флаги или Docker secrets, не включать в образ

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

Ресурсы