Configuración de aplicaciones en Rust: bibliotecas config y dotenv

Entrenador de Python en Línea para Principiantes

Aprende Python fácilmente sin sobrecargarte de teoría. Resuelve tareas prácticas con verificación automática, recibe pistas y escribe código directamente en el navegador, sin instalar nada.

Start Course

Configuración de aplicaciones Rust: bibliotecas config y dotenv



Cualquier aplicación moderna requiere un sistema de configuración flexible: ajustes de base de datos, claves API, puertos del servidor, niveles de registro y otros parámetros. En el ecosistema de Rust existen herramientas potentes para esto: los crates config y dotenv. Permiten combinar configuraciones de diferentes fuentes (archivos, variables de entorno, argumentos de línea de comandos) en una única estructura type-safe.



¿Por qué se necesita una biblioteca separada?

Rust es un lenguaje con tipado estático fuerte. Leer cadenas simples de std::env::var() conduce a múltiples verificaciones y transformaciones manuales. La biblioteca config automatiza este proceso:

  • Soporte de formatos: YAML, JSON, TOML, HJSON, INI, RON
  • Estructura jerárquica de configuraciones con posibilidad de anulación
  • Deserialización automática en estructuras personalizadas a través de serde
  • Combinación de múltiples fuentes con prioridades (archivo < env < CLI)


Instalación

Agregue en Cargo.toml:

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


Ejemplo básico: lectura desde archivo y env

Creemos una estructura para la configuración de la aplicación:

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> { // Cargamos la configuración 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(())}


Archivo config/default.toml:

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

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


Las variables de entorno con el prefijo APP_ anulan los valores del archivo. Por ejemplo, APP_DATABASE__URL cambiará la URL de la base de datos.



Trabajo con dotenv

Para mayor comodidad en el desarrollo, a menudo se usa el archivo .env. El crate dotenv lo carga en las variables de entorno antes de inicializar config:

use dotenv::dotenv;

fn main() { dotenv().ok(); // cargamos .env // luego inicialización de config como en el ejemplo anterior}


Contenido de .env:

APP_SERVER__PORT=3000APP_DATABASE__POOL_SIZE=20


Escenario avanzado: múltiples fuentes

Los proyectos reales requieren combinar configuraciones de diferentes lugares. config permite definir una cadena de fuentes con prioridad:

let config = Config::builder()    // Configuraciones base (baja prioridad)    .add_source(config::File::with_name("config/default"))    // Anulación para un entorno específico    .add_source(config::File::with_name(&format!("config/{}", env::var("APP_ENV").unwrap_or("development"))))    // Variables de entorno (prioridad media)    .add_source(config::Environment::with_prefix("APP"))    // Argumentos de línea de comandos (alta prioridad)    .add_source(config::File::from(std::env::args().nth(1).unwrap_or_default()))    .build()?;


Best Practices

  • Use prefijos para las variables de entorno, para evitar conflictos con variables del sistema

Recommendations