process.env это объект, в котором по одному свойству на каждую переменную окружения, переданную оболочкой вашей программе на Node.js: process.env.PORT, process.env.DATABASE_URL и так далее. Переменная, которую не задали, читается как undefined, а заданная всегда строка. Прочитайте её один раз при запуске, задайте значение по умолчанию и преобразуйте в нужный тип.
Программа вывела shop on port 8080 in eu-west (REGION никто не задавал, поэтому сработало значение по умолчанию), а затем string number: переменная остаётся текстом, пока её не преобразует Number(). Удалите первые два присваивания и запустите снова, чтобы увидеть все значения по умолчанию.
Как задать переменные окружения в терминале
Переменные приходят оттуда, откуда запускают Node.js. В терминале:
// macOS and Linux: for one command
PORT=8080 NODE_ENV=production node app.js
// macOS and Linux: for the rest of the terminal session
export PORT=8080
// Windows PowerShell
$env:PORT = "8080"; node app.js
// Windows cmd.exe
set PORT=8080
node app.js
У хостингов (Heroku, Render, Vercel, Docker, Kubernetes) для этого есть страница настроек или файл, а код читает переменные точно так же.
Всё это строки
Отсюда берётся большинство ошибок с process.env. 'false' и '0' это непустые строки, поэтому они truthy:
Наивная проверка вывела debug is ON для переменной со значением false, поэтому сравнивайте с точной строкой, которую ожидаете. С числами Number(process.env.X) превращает отсутствующее значение в NaN, так что подставляйте значение по умолчанию до преобразования, как в первом примере с ??.
NODE_ENV
NODE_ENV это соглашение, а не возможность Node.js: сам Node.js его никогда не задаёт. Его читают библиотеки. Express, например, убирает stack trace со страниц ошибок, когда там production, а многие инструменты пропускают проверки, нужные только при разработке.
Программа вывела mode: production и verbose logs: false; замените 'production' на 'development', и вторая строка поменяется. Используйте production, development и test, потому что библиотеки проверяют именно эти слова.
Файлы .env: --env-file и dotenv
Набирать каждую переменную перед node быстро надоедает. Файл .env хранит их в папке проекта, по одной на строку:
// .env
PORT=8080
DATABASE_URL=postgres://localhost/shop
API_KEY=dev-key-123
Node.js 20.6 и новее читает его по флагу, без всяких пакетов:
node --env-file=.env app.js
В старых версиях, или если так удобнее, установите пакет dotenv (npm install dotenv) и загрузите его в самом начале входного файла, до любого кода, который читает process.env:
require('dotenv').config(); // copies .env into process.env
console.log(process.env.PORT); // 8080
Ни один из способов не перезаписывает переменную, которая уже задана в оболочке, поэтому настройки продакшена важнее файла.
Падайте сразу, если переменной нет
Если нет адреса базы данных, программа должна остановиться при запуске с понятным сообщением, а не упасть через час на первом запросе:
Программа вывела Missing environment variables: API_KEY; добавьте в начало process.env.API_KEY = 'test';, и она выведет Config OK. В настоящей программе после сообщения вызовите process.exit(1): по ненулевому коду выхода скрипт деплоя или контейнерная платформа понимает, что запуск не удался.
Никогда не коммитьте секреты
Добавьте .env в .gitignore в тот же день, когда создали его. Вместо него закоммитьте .env.example с именами переменных и ненастоящими значениями, чтобы остальные знали, что задать. Ключ, который хоть раз попал в репозиторий, считайте утёкшим и замените, даже если потом удалите коммит.
Часто задаваемые вопросы
Почему process.env.MY_VAR равен undefined?
Переменную не задали в той оболочке, из которой запущен Node.js, или задали в другом терминале. Файл .env тоже не читается сам по себе: запустите Node.js с --env-file=.env или загрузите его через dotenv до того, как читать значение.
Можно ли менять process.env во время работы программы?
Да. Присваивание process.env.X = 'value' меняет переменную для текущего процесса и для дочерних процессов, которые он запустит позже, но никогда для оболочки, из которой запущен Node.js. Присвоенное значение Node.js превращает в строку.
Важен ли регистр в именах переменных окружения?
В Linux и macOS важен: PORT и port это две разные переменные. В Windows нет. Пишите имена заглавными буквами с подчёркиваниями, и вопрос не возникнет.
Может ли браузер читать process.env?
Нет. У браузера нет переменных окружения. Сборщики вроде Vite и Next.js при сборке копируют выбранные переменные во фронтенд-код, а значит, эти значения публичны.