Переменные окружения
Переменные окружения (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всегда возвращает строку