Rust Application Configuration: The `config` Library for Flexible Settings

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

The config Library for Managing Configuration in Rust



When developing applications in Rust, flexible management of settings is an important task. The config library (the config crate) provides a powerful and convenient way to work with configuration files, environment variables, and built-in values. It supports TOML, JSON, YAML, HJSON, INI formats and allows merging settings from multiple sources with priorities.



Installation

Add the dependency to Cargo.toml:

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


Basic Usage

Let's create a simple configuration file Settings.toml:

[server]host = "127.0.0.1"port = 8080

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


Now load it into a Rust application:

use config::{Config, File, Environment};use serde::Deserialize;

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

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

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

fn main() -> Result<(), config::ConfigError> { let settings = Config::builder() .add_source(File::with_name("Settings")) .add_source(Environment::with_prefix("APP")) .build()?;

let app_config: AppConfig = settings.try_deserialize()?; println!("Server: {}:{}", app_config.server.host, app_config.server.port); println!("Database: {}", app_config.database.url); Ok(())}


Support for Multiple Formats

The library automatically detects the format based on the file extension. Example with JSON:

let settings = Config::builder()    .add_source(File::with_name("config.json"))    .add_source(File::with_name("override.yaml").required(false))    .build()?;


Environment Variables

Use a prefix for environment variables to override settings without modifying files:

// Run: APP_SERVER__PORT=9090 cargo runlet settings = Config::builder()    .add_source(File::with_name("Settings"))    .add_source(Environment::with_prefix("APP").separator("__"))    .build()?;


Nested Settings and Arrays

Hierarchical structures are supported:

#[derive(Debug, Deserialize)]struct AppConfig {    features: Vec<String>,    logging: LoggingConfig,}

#[derive(Debug, Deserialize)]struct LoggingConfig { level: String, file: Option<String>,}


Example TOML with arrays:

features = ["auth", "caching", "metrics"]

[logging]level = "info"file = "/var/log/app.log"


Merging Configurations

The library allows layering settings from different sources. Later sources have higher priority:

let settings = Config::builder()    .add_source(File::with_name("default"))      // base settings    .add_source(File::with_name("production").required(false)) // production    .add_source(Environment::with_prefix("APP")) // environment variables    .build()?;


Error Handling and Default Values

Use get() to retrieve individual values with a fallback:

let port: u16 = settings.get("server.port").unwrap_or(8080);let debug: bool = settings.get("debug").unwrap_or(false);


Dynamic Access to Settings

If the configuration structure is unknown in advance, use dynamic access:

let val = settings.get_string("database.url")?;let timeout = settings.get_int("timeout")                    

Recommendations