dotcfg 0.1.0

Flexible config management for Rust CLIs — your path, your format
Documentation

dotcfg

Flexible config management for Rust CLIs — your path, your format.

Why dotcfg?

Most config crates either lock you into a fixed directory strategy or only handle reading. dotcfg gives you full control:

  • Choose ~/.toolname/ or ~/.config/toolname/ — your call
  • TOML or JSON — feature-gated, include only what you need
  • Load the whole config or get/set individual keys without touching the rest
  • Returns None if config doesn't exist — no magic, no forced defaults unless you want them

Installation

# TOML only (default)
dotcfg = "0.1"

# JSON only
dotcfg = { version = "0.1", default-features = false, features = ["json"] }

# Both
dotcfg = { version = "0.1", features = ["json"] }

Quick Start

use dotcfg::DotCfg;
use serde::{Deserialize, Serialize};

#[derive(Serialize, Deserialize, Default)]
struct Config {
    username: String,
    port: u16,
}

fn main() -> Result<(), Box<dyn std::error::Error>> {
    // ~/.mytool/config.toml (default)
    let cfg = DotCfg::new("mytool");

    // Save — creates dir if needed
    cfg.save(&Config { username: "tayo".into(), port: 8080 })?;

    // Load — None if file doesn't exist
    let config: Option<Config> = cfg.load()?;

    // Per-key (no need to load whole struct)
    cfg.set("username", "jane")?;
    let val = cfg.get("user.username")?;

    Ok(())
}

Directory Strategy

// ~/.mytool/config.toml  (default — like .cargo, .ssh)
let cfg = DotCfg::new("mytool");

// ~/.config/mytool/config.toml  (XDG standard, cross-platform)
let cfg = DotCfg::new("mytool").xdg();

// explicit dot (same as default)
let cfg = DotCfg::new("mytool").dot();

Format

// TOML (default)
let cfg = DotCfg::new("mytool");

// JSON (needs `json` feature)
let cfg = DotCfg::new("mytool").json();

// Custom filename
let cfg = DotCfg::new("mytool").json().filename("settings");
// → ~/.mytool/settings.json  (or ~/.config/... with .xdg())

Loading

// Returns None if file doesn't exist — you decide what to do
let config: Option<Config> = cfg.load()?;

// Returns an error if file doesn't exist — useful for CLIs that require setup
let config: Config = cfg.load_or_error()?;

// Creates the file with Default values if it doesn't exist — opt-in
let config: Config = cfg.load_or_default()?;

Per-key Get & Set

Get or set individual keys without loading or overwriting the whole config.

Supports flat and nested (one level: section.field) keys:

// Flat
cfg.get("username")?;
cfg.set("username", "tayo")?;

// Nested → [user] table in TOML / nested object in JSON
cfg.get("user.username")?;
cfg.set("user.username", "tayo")?;

set creates the file/dir if missing and preserves all other keys. Values are stored as strings.

Other Utilities

cfg.exists()?;      // does config file exist?
cfg.dir()?;         // config directory path
cfg.file_path()?;   // full file path
cfg.delete_file()?; // delete file, keep dir
cfg.delete_dir()?;  // delete entire dir

Features

Feature Default Description
toml ✅ TOML format support
json ❌ JSON format support

License

Dual-licensed under MIT OR Apache-2.0. See LICENSE-MIT and LICENSE-APACHE.