Конфигурация приложений на Rust: библиотеки config и dotenv

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Конфигурация приложений Rust: библиотеки config и dotenv

Любое современное приложение требует гибкой системы конфигурации: настройки базы данных, API-ключи, порты сервера, уровни логирования и другие параметры. В экосистеме Rust для этого есть мощные инструменты — крейты config и dotenv. Они позволяют объединять настройки из разных источников (файлы, переменные окружения, аргументы командной строки) в единую типобезопасную структуру.

Зачем нужна отдельная библиотека?

Rust — язык с сильной статической типизацией. Простое чтение строк из std::env::var() приводит к множеству ручных проверок и преобразований. Библиотека config автоматизирует этот процесс:

  • Поддержка форматов: YAML, JSON, TOML, HJSON, INI, RON
  • Иерархическая структура настроек с возможностью переопределения
  • Автоматическая десериализация в пользовательские структуры через serde
  • Объединение нескольких источников с приоритетами (файл < env < CLI)

Установка

Добавьте в Cargo.toml:

[dependencies]
config = "0.14"
serde = { version = "1.0", features = ["derive"] }
dotenv = "0.15"

Базовый пример: чтение из файла и env

Создадим структуру для конфигурации приложения:

use serde::Deserialize;
use config::Config;

#[derive(Debug, Deserialize)]
struct AppConfig {
    server: ServerConfig,
    database: DatabaseConfig,
}

#[derive(Debug, Deserialize)]
struct ServerConfig {
    host: String,
    port: u16,
    workers: u8,
}

#[derive(Debug, Deserialize)]
struct DatabaseConfig {
    url: String,
    pool_size: u32,
}

fn main() -> Result<(), config::ConfigError> {
    // Загружаем конфигурацию
    let config = Config::builder()
        .add_source(config::File::with_name("config/default"))
        .add_source(config::Environment::with_prefix("APP"))
        .build()?;

    let app_config: AppConfig = config.try_deserialize()?;
    println!("{:#?}", app_config);
    Ok(())
}

Файл config/default.toml:

[server]
host = "127.0.0.1"
port = 8080
workers = 4

[database]
url = "postgres://localhost/mydb"
pool_size = 10

Переменные окружения с префиксом APP_ переопределяют значения из файла. Например, APP_DATABASE__URL изменит URL базы данных.

Работа с dotenv

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

use dotenv::dotenv;

fn main() {
    dotenv().ok(); // загружаем .env
    // далее инициализация config как в примере выше
}

Содержимое .env:

APP_SERVER__PORT=3000
APP_DATABASE__POOL_SIZE=20

Продвинутый сценарий: несколько источников

Реальные проекты требуют комбинирования настроек из разных мест. config позволяет задать цепочку источников с приоритетом:

let config = Config::builder()
    // Базовые настройки (низкий приоритет)
    .add_source(config::File::with_name("config/default"))
    // Переопределение для конкретного окружения
    .add_source(config::File::with_name(&format!("config/{}", env::var("APP_ENV").unwrap_or("development"))))
    // Переменные окружения (средний приоритет)
    .add_source(config::Environment::with_prefix("APP"))
    // Аргументы командной строки (высокий приоритет)
    .add_source(config::File::from(std::env::args().nth(1).unwrap_or_default()))
    .build()?;

Best Practices

  • Используйте префиксы для переменных окружения, чтобы избежать конфликтов с системными переменными
  • Разделяйте настройки по окружениям: config/development.toml, config/production.toml
  • Не храните секреты в репозитории — используйте .env (добавьте его в .gitignore) или внешние сервисы (Vault, AWS Secrets Manager)
  • Валидируйте кон

Рекомендаций