#config-file #config-toml

cfgmatic-files

Configuration file discovery and reading with multiple format support

11 releases (7 stable)

Uses new Rust 2024

2.2.0 Feb 20, 2026
2.1.0 Feb 20, 2026
1.1.2 Feb 19, 2026
0.1.6 Feb 17, 2026

#1193 in Filesystem

MIT/Apache

360KB
6.5K SLoC

cfgmatic-files

License Unsafe rustc

Configuration file discovery and reading with multiple format support.

Overview

cfgmatic-files provides a simple, cross-platform way to discover and parse configuration files following platform conventions (via cfgmatic-paths). It supports multiple serialization formats and handles configuration merging with proper priority handling.

Features

  • Multiple Formats: TOML, JSON, YAML (see note below)
  • Cross-platform: Uses cfgmatic-paths for platform-specific directories
  • Priority-based Merging: User > Local > System
  • Type-safe Parsing: Deserialize directly into your structs
  • Flexible Discovery: Find all files or just the first available

YAML Support Notice

LEGACY: The yaml feature is considered legacy. The serde_yaml crate is deprecated by its author and may be removed in future versions. See: https://github.com/dtolnay/serde-yaml/issues/344

Installation

[dependencies]
cfgmatic-files = "0.1"

Enable features as needed:

[dependencies]
cfgmatic-files = { version = "0.1", features = ["toml", "json"] }

Quick Start

Finding Configuration Files

use cfgmatic_files::FileFinder;

// Find all config files for an application
let files = FileFinder::new("myapp").find()?;

for file in &files {
    println!("Found: {} ({:?})", file.path.display(), file.tier);
}

Parsing Configurations

use cfgmatic_files::FileFinder;
use serde::Deserialize;

#[derive(Debug, Deserialize)]
struct Config {
    timeout: u32,
    host: String,
}

let files = FileFinder::new("myapp").find()?;

if let Some(file) = files.first() {
    let config: Config = file.parse()?;
    println!("Timeout: {}, Host: {}", config.timeout, config.host);
}

Loading and Merging

use cfgmatic_files::load_merged;
use serde::Deserialize;

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

// Load and merge all config files (User > Local > System)
let config: Config = load_merged("myapp")?;

Finding First Available

use cfgmatic_files::{load_first, FileFinder};

// Load the first available config file
let config: Option<Config> = load_first("myapp")?;

// Or find the file first
let files = FileFinder::new("myapp").find()?;
if let Some(file) = files.first() {
    // Use file.path() to access the path
    println!("Config file: {}", file.path().display());
}

Configuration Priority

Files are searched and prioritized by tier (highest to lowest):

  1. User (ConfigTier::User): User-specific configs

    • Unix/Linux: ~/.config/myapp/
    • macOS: ~/Library/Application Support/myapp/ (GUI apps)
    • Windows: %APPDATA%\myapp\
  2. Local (ConfigTier::Local): Machine-specific configs

    • Unix/Linux: /usr/local/etc/myapp/, /etc/myapp/
    • macOS: /Library/Application Support/myapp/
    • Windows: %PROGRAMDATA%\myapp\
  3. System (ConfigTier::System): System-wide configs

    • Unix/Linux: /etc/myapp/, /etc/xdg/myapp/
    • Windows: %PROGRAMDATA%\myapp\

When merging configurations, higher tiers override values from lower tiers.

Supported Formats

TOML (default)

# config.toml
timeout = 30
host = "localhost"
let files = FileFinder::new("myapp")
    .formats(&[Format::Toml])
    .find()?;

JSON (default)

{
  "timeout": 30,
  "host": "localhost"
}
let files = FileFinder::new("myapp")
    .formats(&[Format::Json])
    .find()?;

YAML (legacy feature)

timeout: 30
host: localhost
let files = FileFinder::new("myapp")
    .formats(&[Format::Yaml])
    .find()?;

Advanced Usage

Custom Format Selection

use cfgmatic_files::{FileFinder, Format};

// Search for TOML and JSON, preferring TOML
let files = FileFinder::new("myapp")
    .formats(&[Format::Toml, Format::Json])
    .find()?;

Tier-specific Searching

use cfgmatic_files::{FileFinder, ConfigTier};

// Only search user directories
let files = FileFinder::new("myapp")
    .tiers(&[ConfigTier::User])
    .find()?;

Merging Custom Types

use cfgmatic_files::{ConfigFiles, Mergeable};
use serde::Deserialize;

#[derive(Debug, Deserialize, Default)]
struct Config {
    port: u16,
    #[serde(default)]
    database: DatabaseConfig,
}

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

let files = FileFinder::new("myapp").find()?;
let config: Config = files.merge()?;

Examples

# Find and display all config files
cargo run --example find_files

# Load and parse TOML config
cargo run --example load_toml

# Merge multiple config files
cargo run --example merge_configs

Feature Flags

  • default: Enables toml and json features
  • toml: TOML format support (via toml crate)
  • json: JSON format support (via serde_json)
  • yaml: YAML format support (via serde_yaml, legacy)
  • async: Async support via tokio

Relationship to cfgmatic

This crate is part of the cfgmatic configuration framework:

  • cfgmatic-paths: Platform-specific path discovery
  • cfgmatic-files: File discovery and parsing (this crate)
  • cfgmatic: High-level API with environment variables and validation

License

This project is licensed under either of:

at your option.

Contributing

Contributions are welcome! Please see CONTRIBUTING.md for details.

Dependencies

~0.9–4.5MB
~64K SLoC