superconfig 0.1.0

Advanced configuration management built on Figment with hierarchical loading, array merging, and smart format detection
Documentation

SuperConfig

Advanced configuration management with hierarchical cascading, intelligent array merging, smart format detection, and performance optimizations.

Crates.io Documentation License: MIT

Built on Figment's foundation, SuperConfig adds advanced features while maintaining 100% compatibility.

🚀 Core Features

Core Capabilities

  • 🏗️ Hierarchical Configuration: Git-like config inheritance across system → user → project levels

  • 🔄 Advanced Array Merging: Compose configurations with _add/_remove patterns across all sources

  • 🧠 Intelligent Format Detection: Content-based parsing with caching and performance optimizations

  • 🌐 Enhanced Environment Variables: JSON parsing, nested structures, and smart type detection

  • 🔧 Production Optimizations: Lazy loading, modification time caching, and optimized data structures

  • 🔍 Configuration Debugging: Built-in introspection, source tracking, and validation tools

  • 🗣️ Verbosity System: CLI-style debugging with -v, -vv, -vvv levels for troubleshooting configuration issues

  • Production-Ready: Performance optimized for real-world applications

  • Figment Compatible: Seamless upgrade path for existing Figment users

🔌 Enhanced Providers

Universal Provider - Intelligent Format Detection

  • 4-Scenario Detection Strategy: Handles standard files, misnamed files, unknown extensions, and auto-extension search
  • Performance Optimized: Content-based detection with modification time caching
  • Format Support: JSON, TOML, YAML with automatic fallback chains
  • Example: Universal::file("config") tries config.toml, config.yaml, config.json automatically

Nested Provider - Advanced Environment Variables

  • JSON Parsing: APP_FEATURES='["auth", "cache"]'features array
  • Automatic Nesting: APP_DATABASE_HOST=localhostdatabase.host
  • Smart Type Detection: Strings, numbers, booleans, arrays, objects
  • Performance Caching: Optimized parsing with intelligent caching

Empty Provider - Clean Configuration

  • Smart Filtering: Removes empty strings, arrays, objects while preserving meaningful falsy values
  • CLI Integration: Perfect for filtering meaningless CLI arguments
  • Preserves Intent: Keeps false, 0, and other intentional values

Hierarchical Provider - Configuration Cascade

  • Search Hierarchy: ~/.config/app/, ~/.app/, ~/, ancestor directories, current directory
  • Automatic Merging: Later configs override earlier ones with array merging support
  • Git-like Behavior: Similar to .gitconfig hierarchical resolution

🚀 Built-In Features

Array Merging & Export

// Built into SuperConfig - no extension traits needed
let config = SuperConfig::new()
    .with_file("config")                    // Smart format detection
    .with_env("APP_")                       // Enhanced environment variables
    .with_hierarchical_config("myapp");     // Git-style discovery

// Rich export and debugging capabilities
let json = config.as_json()?;              // Export as JSON
let yaml = config.as_yaml()?;              // Export as YAML 
let host = config.get_string("db.host")?;   // Extract values
let exists = config.has_key("redis")?;      // Check existence
let debug = config.debug_config()?;        // Full debug output

🚀 Quick Start

use superconfig::SuperConfig;  // Only import you need
use serde::{Deserialize, Serialize};

#[derive(Debug, Deserialize, Serialize, Default)]
struct AppConfig {
    name: String,
    port: u16,
    features: Vec<String>,
    database: DatabaseConfig,
}

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

let cli_args = AppConfig {
    name: "myapp".to_string(),
    port: 3000,
    ..Default::default()
};

let config: AppConfig = SuperConfig::new()
    .with_defaults(AppConfig::default())        // Set smart defaults
    .with_verbosity(VerbosityLevel::Debug)      // Enable configuration debugging  
    .with_hierarchical_config("myapp")          // System → user → project cascade
    .with_file("config")                        // Auto-detects .toml/.json/.yaml
    .with_env("APP_")                           // JSON parsing + nesting
    .with_cli_opt(Some(cli_args))               // Filtered CLI overrides
    .extract()?;                                // Direct extraction

# Ok::<(), figment::Error>(())

💡 Real-World Examples

Production Configuration Setup

use superconfig::SuperConfig;
use serde::{Deserialize, Serialize};

#[derive(Debug, Deserialize, Serialize, Default)]
struct AppConfig {
    server: ServerConfig,
    database: DatabaseConfig,
    features: Vec<String>,
    cors: CorsConfig,
    logging: LoggingConfig,
}

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

let config: AppConfig = SuperConfig::new()
    .with_defaults(AppConfig {
        server: ServerConfig {
            host: "127.0.0.1".to_string(),
            port: 8080,
            workers: 4,
        },
        features: vec!["basic".to_string()],
        ..Default::default()
    })
    .with_hierarchical_config("myapp")      // System-wide configs
    .with_file("config")                    // Project config
    .with_env("MYAPP_")                     // Environment overrides
    .with_cli_opt(cli_args)                 // Runtime overrides
    .extract()?;

# Ok::<(), figment::Error>(())

Hierarchical Configuration Discovery

// with_hierarchical_config("myapp") searches in priority order:
// 
// 1. ~/.config/myapp/myapp.{toml,yaml,json}    (XDG system config)
// 2. ~/.myapp/myapp.{toml,yaml,json}           (User home config)  
// 3. ~/myapp.{toml,yaml,json}                  (Home root config)
// 4. ../../myapp.{toml,yaml,json}              (Ancestor directories)
// 5. ../myapp.{toml,yaml,json}                 (Parent directory)
// 6. ./myapp.{toml,yaml,json}                  (Current directory)
//
// Later configs override earlier ones with smart array merging

let config = SuperConfig::new()
    .with_hierarchical_config("myapp")
    .with_env("MYAPP_")
    .extract()?;

Advanced Array Composition

# ~/.config/myapp/myapp.toml (system defaults)
[server]
features = ["auth", "logging", "metrics"]
ignore_paths = ["*.tmp", "*.log"]

[cors]
allowed_origins = ["https://app.example.com"]
# ./myapp.toml (project overrides)
[server] 
features_add = ["debug", "hot-reload"]      # Adds to existing array
features_remove = ["metrics"]               # Removes from array
ignore_paths_add = ["*.cache", "build/*"]    # Extends ignore patterns

[cors]
allowed_origins_add = ["http://localhost:3000"]  # Add dev origin

# Final result:
# features = ["auth", "logging", "debug", "hot-reload"]
# ignore_paths = ["*.tmp", "*.log", "*.cache", "build/*"] 
# allowed_origins = ["https://app.example.com", "http://localhost:3000"]

Advanced Environment Variable Scenarios

# Simple nesting
export MYAPP_DATABASE_HOST="localhost"              # → database.host
export MYAPP_DATABASE_PORT="5432"                   # → database.port

# JSON arrays and objects
export MYAPP_FEATURES='["auth", "cache", "metrics"]' # → features (parsed as array)
export MYAPP_REDIS_CONFIG='{"host": "redis.example.com", "pool_size": 10}' # → redis.config

# Array composition via environment
export MYAPP_FEATURES_ADD='["debug"]'               # Adds "debug" to features array
export MYAPP_FEATURES_REMOVE='["cache"]'            # Removes "cache" from features

# Nested object construction  
export MYAPP_SERVER_TLS_CERT_PATH="/etc/ssl/cert.pem"
export MYAPP_SERVER_TLS_KEY_PATH="/etc/ssl/key.pem"
# → server.tls.cert_path and server.tls.key_path

Configuration Debugging & Introspection

use superconfig::{SuperConfig, AccessExt};

let config = SuperConfig::new()
    .with_hierarchical_config("myapp")
    .with_file("config")
    .with_env("MYAPP_");

// Export in different formats
let json_config = config.as_json()?;           // Pretty JSON
let yaml_config = config.as_yaml()?;           // YAML format
let toml_config = config.as_toml()?;           // TOML format

// Value extraction and validation
let db_host = config.get_string("database.host")?;
let features = config.get_array::<String>("features")?;
let has_redis = config.has_key("redis.enabled")?;
let all_keys = config.keys()?;

// Full debug output with source tracking
let debug_output = config.debug_config()?;
println!("{}", debug_output);
// Shows final merged config + which providers contributed each value

// Source metadata for troubleshooting
let sources = config.debug_sources();
for source in sources {
    println!("Provider: {:?}", source);
}

# Ok::<(), figment::Error>(())

Performance Features

let config = SuperConfig::new()
    .with_hierarchical_config("prod-app")
    .with_file("config")
    .with_env_ignore_empty("APP_")
    .extract()?;

# Ok::<(), figment::Error>(())

🎯 When to Use SuperConfig

✅ Use Cases

  • Complex applications with multiple environments
  • Advanced configuration patterns and array merging
  • Performance-critical systems
  • Multi-source configuration loading
  • Development teams needing debugging capabilities
  • Production deployments requiring robust error handling

🔄 Figment Migration

Existing Figment users can easily migrate to SuperConfig's enhanced capabilities.

⚡ Performance

  • Lazy Loading: Files cached by modification time
  • Smart Detection: Content-based format detection
  • Conditional Processing: Array merging only when needed
  • Efficient Caching: Parsed data cached for reuse

🛠️ Advanced Features

Configuration Validation

use superconfig::{SuperConfig, AccessExt};
use serde::{Deserialize, Serialize};

#[derive(Debug, Deserialize, Serialize)]
struct DatabaseConfig {
    host: String,
    port: u16,
    #[serde(default = "default_max_connections")]
    max_connections: u32,
}

fn default_max_connections() -> u32 { 100 }

let config = SuperConfig::new()
    .with_hierarchical_config("myapp")
    .with_env("APP_");

// Validate configuration exists and is accessible
if !config.has_key("database.host")? {
    eprintln!("Warning: No database host configured");
}

// Extract with validation
let db_config: DatabaseConfig = config.extract_inner("database")?;

Error Handling & Diagnostics

use superconfig::{SuperConfig, AccessExt};

let config = SuperConfig::new()
    .with_file("config")
    .with_env("APP_");

match config.extract::<AppConfig>() {
    Ok(cfg) => println!("Configuration loaded successfully"),
    Err(e) => {
        eprintln!("Configuration error: {}", e);
        
        // Debug what went wrong
        eprintln!("Debug info:\n{}", config.debug_config()?);
        
        // Show all sources
        for source in config.debug_sources() {
            eprintln!("Source: {:?}", source);
        }
    }
}

Custom Provider Integration

use superconfig::{SuperConfig, ExtendExt};
use figment::Provider;

// Your custom provider
struct DatabaseProvider {
    connection_string: String,
}

impl Provider for DatabaseProvider {
    // Implementation details...
}

let config = SuperConfig::new()
    .with_hierarchical_config("myapp")
    .with_provider(DatabaseProvider { /* ... */ })  // Automatic array merging
    .with_env("APP_");

📚 Documentation & Resources

🤝 Contributing

We welcome contributions! SuperConfig is designed to become the universal configuration standard.

  • Issues: Bug reports, feature requests
  • Pull Requests: Code improvements, documentation, examples
  • Discussions: Architecture decisions, use cases, integrations

📄 License

Licensed under the MIT License. See LICENSE for details.


SuperConfig - Configuration management that scales with your application.