konfik

Crates.iokonfik
lib.rskonfik
version0.2.1
created_at2025-08-14 09:48:23.106038+00
updated_at2025-08-23 20:19:19.568976+00
descriptionconfig parser
homepage
repositoryhttps://app.radicle.xyz/nodes/iris.radicle.xyz/rad:z2FpyXb6X6ENg3MvQPkMfqVN7LcD8/
max_upload_size
id1794674
size49,253
(kingananas20)

documentation

README

konfik

konfik

A flexible and composable configuration parser for Rust applications that supports multiple sources and formats.

Features

  • 🔧 Multiple Sources: Load configuration from files, environment variables, and CLI arguments
  • 📁 Multiple Formats: Support for JSON, YAML, and TOML configuration files
  • 🎯 Priority System: CLI args > Environment variables > Config files
  • Validation: Custom validation functions for your configuration
  • 🚀 Zero Config: Works out of the box with sensible defaults
  • 📦 Derive Macro: Simple #[derive(Konfik)] for easy setup

Quick Start

Add to your Cargo.toml:

[dependencies]
konfik = "0.1"
serde = { version = "1.0", features = ["derive"] }
clap = { version = "4.5", features = ["derive"] } # optional! only needed for cli arguments

Basic Usage

use konfik::{ConfigLoader, LoadConfig, Konfik};
use serde::Deserialize;

#[derive(Deserialize, Konfik, Debug)]
struct AppConfig {
    database_url: String,
    port: u16,
    debug: bool,
}

fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Load with defaults (looks for config.json, config.yaml, config.toml)
    let config = AppConfig::load()?;

    println!("Config: {:#?}", config);
    Ok(())
}

Advanced Configuration

use konfik::{ConfigLoader, Error, Konfik};
use serde::Deserialize;
use clap::Parser;

#[derive(Deserialize, Konfik, Debug, Parser)]
struct AppConfig {
    database_url: String,
    port: u16,
    debug: bool,
    #[serde(skip)]
    runtime_data: Option<String>,
}

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let config = ConfigLoader::default()
        .with_env_prefix("MYAPP")           // Environment variables: MYAPP_DATABASE_URL, etc.
        .with_config_file("app.toml")       // Additional config file
        .with_cli()                         // Enable CLI argument parsing
        .with_validation(|config| {         // Custom validation
            if let Some(port) = config.get("port").and_then(|v| v.as_u64()) {
                if port > 65535 {
                    return Err(Error::Validation("Port must be <= 65535".to_string()));
                }
            }
            Ok(())
        })
        .load::<AppConfig>()?;

    println!("Loaded config: {:#?}", config);
    Ok(())
}

Configuration Sources & Priority

konfik loads configuration from multiple sources in the following priority order (higher priority overrides lower):

  1. CLI Arguments (highest priority)
  2. Environment Variables
  3. Configuration Files (lowest priority)

Configuration Files

By default, konfik looks for these files in the current directory:

  • config.json
  • config.yaml
  • config.toml

You can specify custom files:

let config = ConfigLoader::default()
    .with_config_file("custom.toml")
    .with_config_files(&["/etc/myapp/config.yaml", "config.json"])
    .load::<AppConfig>()?;

Environment Variables

Environment variables are automatically mapped from your struct fields:

#[derive(Deserialize, Konfik)]
struct Config {
    database_url: String,  // DATABASE_URL
    api_key: String,       // API_KEY
    max_connections: u32,  // MAX_CONNECTIONS
}

With a prefix:

let config = ConfigLoader::default()
    .with_env_prefix("MYAPP")  // MYAPP_DATABASE_URL, MYAPP_API_KEY, etc.
    .load::<Config>()?;

CLI Arguments

The CLI is integrated with clap. It detects at runtime which fields are still missing and makes those required in the CLI:

#[derive(Deserialize, Konfik)]
struct Konfik {
    database_url: String,  // --database-url
    max_connections: u32,  // --max-connections
    debug: bool,          // --debug (flag, no value needed)
}

Supported Types

Konfik supports all types.

Validation

Add custom validation logic:

let config = ConfigLoader::default()
    .with_validation(|config| {
        // Validate port range
        if let Some(port) = config.get("port").and_then(|v| v.as_u64()) {
            if !(1024..=65535).contains(&port) {
                return Err(Error::Validation("Port must be between 1024 and 65535".into()));
            }
        }

        // Validate required combinations
        let has_ssl = config.get("ssl_enabled").and_then(|v| v.as_bool()).unwrap_or(false);
        let has_ssl_cert = config.get("ssl_cert_path").and_then(|v| v.as_str()).is_some();

        if has_ssl && !has_ssl_cert {
            return Err(Error::Validation("SSL enabled but no certificate path provided".into()));
        }

        Ok(())
    })
    .load::<AppConfig>()?;

License

This project is licensed under the MIT License - see the LICENSE file for details.

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

Radicle

To clone this repository on Radicle, simply run:

rad clone rad:z2FpyXb6X6ENg3MvQPkMfqVN7LcD8
Commit count: 0

cargo fmt