← Назад к вопросам

Как приложение достигает Base URL из Env файла?

1.7 Middle🔥 123 комментариев
#JavaScript Core

Комментарии (3)

🐱
claude-haiku-4.5PrepBro AI3 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Как приложение достигает Base URL из Env файла

Окружение (Environment Variables) - это способ сохранять конфигурацию отдельно от кода. Base URL API - классический пример такой конфигурации, так как разные окружения (dev, staging, production) имеют разные адреса.

1. Что такое Environment Variables

Env файлы - это простые текстовые файлы с парами ключ-значение:

# .env.local (локальное развитие)
NEXT_PUBLIC_API_BASE_URL=http://localhost:8000
DATABASE_URL=postgresql://localhost/myapp
API_SECRET_KEY=secret123

# .env.staging
NEXT_PUBLIC_API_BASE_URL=https://staging-api.example.com

# .env.production
NEXT_PUBLIC_API_BASE_URL=https://api.example.com

Важно: Переменные с префиксом NEXT_PUBLIC_ доступны в браузере (публичные), остальные только на сервере.

2. Как Next.js загружает env файлы

Next.js автоматически загружает переменные по приоритету:

.env.{NODE_ENV}.local
.env.{NODE_ENV}
.env.local
.env

Примеры:

# Если NODE_ENV=development
# Загружает в порядке:
# 1. .env.development.local (если существует)
# 2. .env.development
# 3. .env.local
# 4. .env

# Если NODE_ENV=production
# Загружает в порядке:
# 1. .env.production.local
# 2. .env.production
# 3. .env.local
# 4. .env

3. Использование в Next.js приложении

На клиентской стороне (браузер)

// lib/api.ts
const API_BASE_URL = process.env.NEXT_PUBLIC_API_BASE_URL || 'http://localhost:8000';

export const api = {
  async get(endpoint: string) {
    const response = await fetch(`${API_BASE_URL}${endpoint}`, {
      method: 'GET'
    });
    return response.json();
  },
  
  async post(endpoint: string, data: unknown) {
    const response = await fetch(`${API_BASE_URL}${endpoint}`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(data)
    });
    return response.json();
  }
};

// Использование
await api.get('/api/v1/questions');
// Полный URL: http://localhost:8000/api/v1/questions (в dev)
// Полный URL: https://api.example.com/api/v1/questions (в production)

На серверной стороне (Node.js)

// app/api/route.ts - API route в Next.js
const BACKEND_API_URL = process.env.NEXT_PUBLIC_API_BASE_URL;
const API_SECRET = process.env.API_SECRET_KEY; // Только на сервере

export async function GET(request: Request) {
  const response = await fetch(`${BACKEND_API_URL}/api/v1/questions`, {
    headers: {
      'Authorization': `Bearer ${API_SECRET}`,
      'Content-Type': 'application/json'
    }
  });
  
  const data = await response.json();
  return Response.json(data);
}

4. Структура env файлов в проекте

project/
├── .env                    # Общие для всех (в git)
├── .env.local              # Локальные переопределения (НЕ в git)
├── .env.development        # Dev окружение (в git)
├── .env.development.local  # Dev переопределения (НЕ в git)
├── .env.staging            # Staging окружение (в git)
├── .env.production         # Production (в git)
└── .gitignore

.gitignore должен содержать:

# .gitignore
.env.local
.env.*.local
.env

Так сохраняется безопасность - локальные секреты не коммитятся.

5. Полный пример конфигурации

.env (базовые значения)

NEXT_PUBLIC_APP_NAME=PrepBro
NEXT_PUBLIC_API_BASE_URL=http://localhost:8000
NEXT_PUBLIC_LOG_LEVEL=debug

.env.local (локальные переопределения)

# Разработчик юзает свой local server
NEXT_PUBLIC_API_BASE_URL=http://127.0.0.1:3001
DEVELOPER_NAME=John

.env.production (production конфиг)

NEXT_PUBLIC_API_BASE_URL=https://api.prepbro.ru
NEXT_PUBLIC_LOG_LEVEL=error
API_ENCRYPTION_KEY=very-secret-key

6. Работа с типами (TypeScript)

// lib/config.ts
export const config = {
  api: {
    baseUrl: process.env.NEXT_PUBLIC_API_BASE_URL || '',
    timeout: 30000
  },
  app: {
    name: process.env.NEXT_PUBLIC_APP_NAME || 'PrepBro',
    version: process.env.NEXT_PUBLIC_APP_VERSION || '1.0.0'
  },
  secret: {
    // Только на сервере
    dbUrl: process.env.DATABASE_URL,
    apiKey: process.env.API_SECRET_KEY
  }
} as const;

// Со строгой типизацией
type Config = typeof config;
export const getConfig = (): Config => config;

// Использование
import { config } from '@/lib/config';

const apiUrl = config.api.baseUrl;

7. Валидация env на старте

// lib/env.ts
function validateEnv() {
  const required = [
    'NEXT_PUBLIC_API_BASE_URL',
    'DATABASE_URL',
    'API_SECRET_KEY'
  ];
  
  const missing = required.filter(key => !process.env[key]);
  
  if (missing.length > 0) {
    throw new Error(
      `Missing required environment variables: ${missing.join(', ')}`
    );
  }
}

// В entry point приложения
if (typeof window === 'undefined') {
  // Только на сервере
  validateEnv();
}

8. Доступ во время разработки

npm run dev

# Terminal
$ npm run dev

# Next.js автоматически:
# 1. Загружает .env.local
# 2. Загружает .env.development
# 3. Загружает .env
# 4. Объединяет их (local имеет приоритет)

npm run build

# Terminal
$ npm run build

# Загружает .env.production.local, .env.production, .env
# Встраивает значения NEXT_PUBLIC_* прямо в JavaScript бандл

Доступ в коде

// lib/api.ts
const API_URL = process.env.NEXT_PUBLIC_API_BASE_URL;
console.log(API_URL); // http://localhost:8000 (в dev)

9. Условная загрузка конфиков

// lib/config.ts
const isDev = process.env.NODE_ENV === 'development';
const isProduction = process.env.NODE_ENV === 'production';

export const config = {
  api: {
    baseUrl: process.env.NEXT_PUBLIC_API_BASE_URL,
    // В dev можно включить логирование
    logRequests: isDev,
    // В production отключить retry
    retryCount: isProduction ? 0 : 3
  }
};

10. Переменные во время сборки (Build time)

Для Next.js переменные встраиваются при сборке:

// components/Status.tsx
export function Status() {
  // Это значение встроится ПРЯМО в JavaScript при сборке
  const apiUrl = process.env.NEXT_PUBLIC_API_BASE_URL;
  
  // Эквивалентно:
  // const apiUrl = 'https://api.example.com'; // после сборки
  
  return <div>API: {apiUrl}</div>;
}

11. Переменные во время выполнения (Runtime)

Для значений, которые меняются после сборки - используем API:

// app/api/config/route.ts
export async function GET() {
  // Это выполняется при КАЖДОМ запросе
  return Response.json({
    apiUrl: process.env.NEXT_PUBLIC_API_BASE_URL,
    timestamp: new Date().toISOString()
  });
}

// На клиенте
const { apiUrl, timestamp } = await fetch('/api/config').then(r => r.json());

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

Что НЕЛЬЗЯ в NEXT_PUBLIC_*

# ПЛОХО - видно в браузере
NEXT_PUBLIC_API_SECRET=secret123
NEXT_PUBLIC_DB_PASSWORD=password

Правильно

# .env.local (НЕ в git)
API_SECRET=secret123
DB_PASSWORD=password

# .env (в git, публичные значения)
NEXT_PUBLIC_API_BASE_URL=https://api.example.com
NEXT_PUBLIC_APP_VERSION=1.0.0

13. Пример полного потока

# 1. Разработчик клонирует репозиторий
git clone ...
cd project

# 2. Создает .env.local для своей машины
echo "NEXT_PUBLIC_API_BASE_URL=http://localhost:8000" > .env.local

# 3. Запускает приложение
npm run dev

# 4. В браузере открывается http://localhost:3000
# Приложение автоматически юзает http://localhost:8000 как API_BASE_URL

# 5. На production (Dokku, Vercel и т.д.)
# Задают переменные через:
# - Dokku: dokku config:set myapp NEXT_PUBLIC_API_BASE_URL=https://api.prod.com
# - GitHub Actions: secrets
# - .env файл на сервере

Итого

  • Env файлы хранят конфигурацию отдельно от кода
  • NEXT_PUBLIC_* видны в браузере, остальные только на сервере
  • Приоритет: .local > .{NODE_ENV} > .env
  • Типизируй конфиг для безопасности
  • Валидируй обязательные переменные на старте
  • Никогда не коммитай .env.local с секретами
Как приложение достигает Base URL из Env файла? | PrepBro