Как работать с переменными окружения и dotenv в Node.js?

JuniorNode.js · Backend·Обновлено 13 августа 2026
Коротко
Переменные окружения доступны через объект process.env. Пакет dotenv позволяет загружать их из файла .env в локальной разработке, вызвав dotenv.config() в начале приложения.

Переменные окружения в Node.js

Переменные окружения — это пары «ключ-значение», которые задаются на уровне операционной системы или CI/CD-платформы и позволяют разделить конфигурацию и код. В Node.js они доступны через глобальный объект process.env.

console.log(process.env.NODE_ENV); // 'production', 'development' и т.д.
console.log(process.env.PORT);     // '3000'

Важно: все значения process.env являются строками (или undefined), поэтому числа и булевы значения нужно преобразовывать явно.

Пакет dotenv

В локальной разработке удобно хранить переменные в файле .env в корне проекта. Пакет dotenv читает этот файл и добавляет переменные в process.env.

Установка

npm install dotenv

Использование

Вызов dotenv.config() должен быть самым первым в точке входа приложения — до любых импортов, которые используют process.env.

// Файл: src/index.js
require('dotenv').config();

const express = require('express');
const app = express();

const PORT = Number(process.env.PORT) || 3000;
app.listen(PORT, () => console.log(`Сервер запущен на порту ${PORT}`));

Файл .env

PORT=3000
DB_HOST=localhost
DB_USER=root
DB_PASSWORD=secret
JWT_SECRET=my_super_secret_key

Безопасность

  • Файл .env никогда не коммитится в репозиторий. Добавьте его в .gitignore.
  • Создайте .env.example с ключами без значений — как шаблон для новых разработчиков.
  • В production переменные задаются напрямую через платформу (Heroku, AWS, Docker, GitHub Actions) без использования dotenv.

Структура конфига

Хорошая практика — централизовать чтение переменных в отдельном модуле config.js, чтобы не обращаться к process.env напрямую по всему коду.

// Файл: src/config.js
require('dotenv').config();

module.exports = {
  port: Number(process.env.PORT) || 3000,
  db: {
    host: process.env.DB_HOST || 'localhost',
    user: process.env.DB_USER,
    password: process.env.DB_PASSWORD,
  },
  jwtSecret: process.env.JWT_SECRET,
};
// Файл: src/index.js
const config = require('./config');

console.log(config.port); // 3000

Разные окружения

Для разделения конфигураций по окружениям используют несколько .env-файлов:

  • .env — значения по умолчанию
  • .env.development — для разработки
  • .env.production — для продакшена (не коммитится)

Пакет dotenv поддерживает указание пути к файлу:

require('dotenv').config({ path: `.env.${process.env.NODE_ENV}` });

Валидация переменных

Для critical-конфигурации используют схему-валидатор (например, пакет joi или zod), чтобы приложение не запустилось при отсутствии обязательных переменных.

const requiredVars = ['DB_USER', 'DB_PASSWORD', 'JWT_SECRET'];
requiredVars.forEach((key) => {
  if (!process.env[key]) {
    throw new Error(`Отсутствует обязательная переменная окружения: ${key}`);
  }
});

Что хочет услышать интервьюер

Кандидат знает, что переменные окружения доступны через process.env и что все значения — строки

Кандидат понимает, зачем нужен dotenv и как его инициализировать в самом начале точки входа

Кандидат осознаёт, что .env нельзя коммитить, и упоминает .gitignore и .env.example

Кандидат понимает разницу между локальной разработкой (dotenv) и production (переменные платформы)

Кандидат знает, что числа и булевы значения нужно явно приводить к нужному типу

Пример: Централизованный конфиг с валидацией на TypeScript

// .env
// PORT=3000
// DB_URL=postgres://localhost:5432/mydb
// JWT_SECRET=super_secret

// src/config.ts
import 'dotenv/config'; // современный способ — без вызова .config()

const config = {
  port: Number(process.env.PORT) || 3000,
  dbUrl: process.env.DB_URL as string,
  jwtSecret: process.env.JWT_SECRET as string,
};

// Валидация обязательных переменных при старте
const required: Array<keyof typeof config> = ['dbUrl', 'jwtSecret'];
for (const key of required) {
  if (!config[key]) {
    throw new Error(`Отсутствует обязательная переменная: ${key}`);
  }
}

export default config;

Пример: Валидация через zod (продвинутый вариант)

// Пример с zod для строгой типизации конфига
import { z } from 'zod';
import 'dotenv/config';

const envSchema = z.object({
  PORT: z.string().transform(Number).default('3000'),
  DB_URL: z.string().url(),
  JWT_SECRET: z.string().min(16),
  NODE_ENV: z.enum(['development', 'production', 'test']).default('development'),
});

// parse бросит ошибку с подробным описанием, если схема не совпадает
const env = envSchema.parse(process.env);

export default env;

Типичные ошибки

Коммит файла .env в репозиторий с реальными секретами

Вызов dotenv.config() после импортов, которые уже читают process.env — переменные не успевают загрузиться

Использование dotenv в production вместо переменных платформы

Обращение к process.env напрямую по всему коду вместо централизованного config-модуля

Забывают, что process.env возвращает строку, и сравнивают PORT === 3000 вместо Number(PORT) === 3000

Лучшие курсы по теме

изображение курса

Docker и Ansible

Антон Ларичев
AI-тренажерыAI-тренажеры
Гарантия
Бонусы
иконка звёздочки рейтинга4.7
3 999 ₽ 6 990 ₽
Подробнее
изображение курса

Node.js с нуля

Антон Ларичев
AI-тренажерыAI-тренажеры
Практика в студииПрактика в студии
Гарантия
Бонусы
иконка звёздочки рейтинга4.8
3 999 ₽ 6 990 ₽
Подробнее
изображение курса

Nest.js с нуля

Антон Ларичев
AI-тренажерыAI-тренажеры
Практика в студииПрактика в студии
Гарантия
Бонусы
иконка звёздочки рейтинга4.6
3 999 ₽ 6 990 ₽
Подробнее