⚙️ Layered configuration system for Rust applications (with strong support for 12-factor applications).

Overview

config-rs

Rust Build Status Crates.io Docs.rs

Layered configuration system for Rust applications (with strong support for 12-factor applications).

  • Set defaults
  • Set explicit values (to programmatically override)
  • Read from JSON, TOML, YAML, HJSON, INI, RON, JSON5 files
  • Read from environment
  • Loosely typed — Configuration values may be read in any supported type, as long as there exists a reasonable conversion
  • Access nested fields using a formatted path — Uses a subset of JSONPath; currently supports the child ( redis.port ) and subscript operators ( databases[0].name )

Usage

[dependencies]
config = "0.11"
  • ini - Adds support for reading INI files
  • json - Adds support for reading JSON files
  • hjson - Adds support for reading HJSON files
  • yaml - Adds support for reading YAML files
  • toml - Adds support for reading TOML files
  • ron - Adds support for reading RON files
  • json5 - Adds support for reading JSON5 files

See the documentation or examples for more usage information.

License

config-rs is primarily distributed under the terms of both the MIT license and the Apache License (Version 2.0).

See LICENSE-APACHE and LICENSE-MIT for details.

Comments
  • Expose ValueKind

    Expose ValueKind

    Would it be possible to expose ValueKind from value.rs to allow some introspection?

    ie, change: pub use value::Value; in lib.rs to pub use value::{Value, ValueKind};

    enhancement 
    opened by j-t-d 23
  • Is the project maintained?

    Is the project maintained?

    Hello! config is a key component in many of my projects and I'd like to contribute back some functionality/bug fixes. Looking at PRs and issues, there seems to have been little to no activity on the project for the past 10 months or so.

    Should the project be considered unmaintained or is it just temporary? Not interested in pressuring you to work on it, just trying to understand if, instead of contributing PRs, it might make more sense to start a fork to evolve it.

    opened by LukeMathWalker 22
  • Unable to deserialize unsigned integers

    Unable to deserialize unsigned integers

    When implementing config::ValueKind for a custom type, the error invalid type: unsigned integer 64 bit '128', expected an signed 64 bit or less integer for key 'inner.unsigned' is thrown if the custom type contains a unsigned integer. The following is a minimum example:

    #[derive(Deserialize, Eq, PartialEq, Debug)]
    struct Container<T> {
        inner: T,
    }
    
    #[derive(Deserialize, Eq, PartialEq, Debug)]
    struct Unsigned {
        unsigned: u16,
    }
    
    impl Default for Unsigned {
        fn default() -> Self {
            Self { unsigned: 128 }
        }
    }
    
    impl From<Unsigned> for config::ValueKind {
        fn from(unsigned: Unsigned) -> Self {
            let mut properties = HashMap::default();
            properties.insert(
                "unsigned".to_string(),
                config::Value::from(unsigned.unsigned),
            );
    
            Self::Table(properties)
        }
    }
    
    assert_eq!(
        Container {
            inner: Unsigned::default()
        },
        config::Config::builder()
            .set_default("inner", Unsigned::default())
            .unwrap()
            .build()
            .unwrap()
            .try_deserialize::<Container<Unsigned>>()
            .unwrap()
    );
    
    opened by thrykol 17
  • config-rs broken since rust 1.48

    config-rs broken since rust 1.48

    We're trying to use config-rs using the latest rust nightly-1.49-0, and we're getting:

    thread 'main' panicked at 'attempted to leave type `linked_hash_map::Node<std::string::String, value::Value>` uninitialized
    , which is invalid', /home/tyler/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/
    mem/mod.rs:659:9
    

    I see this is also failing on your travis build too:

    https://travis-ci.org/github/mehcode/config-rs/jobs/734764347#L291

    cc @Nutomic

    opened by dessalines 13
  • Add AsyncSource with tests, docs and examples

    Add AsyncSource with tests, docs and examples

    Resolves #148

    This pull request adds a new type of source - AsyncSource, that supports async fn. Also, it modifies the builder in order to handle it properly. Builder implementation based on this article.

    There is no implementation of such a source inside the library since there are various runtimes to choose from as explained in the rustdocs in this pull request.

    One minor change - the type of Result in regular Source has been changed from type synonym defined inside the library to std's Result since ... type synonym was not exported from the crate.

    Json5 tests have been modified for Windows. There was some issue with line endings I was not able to resolve in error message tests. CI for this package runs on Linux, so test will run.

    opened by szarykott 12
  • Adds 'try_parsing' option for Environment

    Adds 'try_parsing' option for Environment

    This can be particularly helpful for MY_SERVER_PORT=4334 cargo run

    I know that serde's hints should do this because of the deserialize_* functions, but there are cases where it uses deserialize_any (for me this happened when refactoring to a nested struct in an enum). Maybe there's a better serde pattern for that/this?

    opened by joelgallant 11
  • Decide on a standard, default convention for configuration

    Decide on a standard, default convention for configuration

    In the spirit of making this library easier to get into and use, I'm thinking we should recommend a convention for configuration (that could, of course, be disabled with feature flags).

    1 - ./config folder with ./config/default.toml and ./config/{env}.toml

    config::merge(config::File::with_name("default").path("config"));
    config::merge(config::File::with_name(env!("RUST_ENV")).path("config").required(false));
    config::merge(config::Environment::new(""));
    

    2 - ./Settings.toml / ./Settings.{env}.toml

    config::merge(config::File::with_name("Settings"));
    config::merge(config::File::with_name(&format!("Settings.{}", env!("RUST_ENV"))).required(false));
    config::merge(config::Environment::new(""));
    

    3 - ./Settings.toml with namespaces

    config::merge(config::File::with_name("Settings").namespace(env!("RUST_ENV")).required(false));
    config::merge(config::Environment::new(""));
    

    An example of 3:

    [development]
    debug = true
    
    [production]
    debug = false
    

    • This is using a unwritten feature of config::File to auto-detect the file type

    The idea is that the equivalent of the above is done automatically. I'm partial to 3 but I'm open to other suggestions.

    opened by mehcode 11
  • Environment variable names are converted to lower case

    Environment variable names are converted to lower case

    Environment variable names are converted to lower case internally. This is surprising undocumented behavior. We want to be able to override values from a configuration file with environment variables. It would be natural to use the same spelling (not counting the prefix), but this doesn't work if the configuration file keys are upper case. To make it work, the configuration file keys must be lower case.

    config.toml

    FOO="You can't override me!"
    bar="You can override me just fine."
    

    In the shell

    APP_FOO="Why are you ignoring me?" APP_BAR="Yay! New bar." ./target/debug/app
    

    I was using TOML for the config file and bash for the shell, if it matters.

    opened by pictographer 10
  • Release v0.12.0

    Release v0.12.0

    I have been thinking about releasing a v0.12.0 a few times already, but I guess we should tackle it.

    There is a milestone of a few things I wanted to have in the release, but given that we already have a lot of changes, I would be okay with moving them to the v0.13.0 release.

    What do you think, especially @szarykott and @danieleades ? Lets discuss!


    Also, I need to double-check whether I can make releases on crates.io ! :laughing:

    opened by matthiasbeyer 10
  • Create the ConfigBuilder

    Create the ConfigBuilder

    This is a draft PR to show an idea of how could ConfigBuilder look like.

    It does not bring a lot of new functionality. It just splits Config that was a mutable configuration combined with a builder into two separate structs. It brings certain benefits:

    • Config is no longer refreshed when a new source is added
    • More from the clean code perspective, it lifts concepts of "mutable" and "frozen" config to type level, thus mitigating runtime errors. It is a clean code issue, as Config could not be frozen before as it was a dead private API.

    Immutability is considered good programming practice, but not everyone might like it. I'd like to hear the opinions of users of the library - do you mutate config often after application initial bootstrap, do you consider such a mutability a needed feature?

    I do not intend to push it in its current form, it is just to showcase an idea. To consider it mergeable discussion has to take place regarding few subjects:

    • is it the correct way to go
    • should old ways be deprecated as it is done now or should they be removed

    In the current state there is a lot of deprecation warnings, so please do not mind them now and focus on more high-level aspects of this PR.

    I attach a graph of the intended workflow so that it is easier to see the big picture. image

    opened by szarykott 10
  • Value::try_into makes use of TryInto difficult

    Value::try_into makes use of TryInto difficult

    I'd like to write some conversions for my own structs from instances of Value, and std::convert::TryFrom / TryInto are good choices for this. However, the existence of a try_into method on the struct, unrelated to these traits, shadows the trait method.

    Could the try_into method be renamed into try_deserialize or something of the sort?

    help wanted 
    opened by djmitche 10
  • Enh Req: Introduce Config metadata for troubleshoot of override/layered values

    Enh Req: Introduce Config metadata for troubleshoot of override/layered values

    Hi, in many situations when multiple sources of configurations are used - it's beneficial to have ability of Config metadata to tell which value came from which source and became effective/actual at the end of sources processing.

    Implementation of this could add extra feature, for example "config-meta" and once used/enabled - later have method like "get_meta" or "dump_meta".

    So if let say I have something like such for config construction out of 2 sources:

    fn make_config() -> Config {
      let current_env = env::var("ENV").unwrap();
      Config::builder()
          .add_source(File::new("env/service", FileFormat::Yaml))
          .add_source(File::new(("env/service-".to_string() + &current_env).as_str(), FileFormat::Yaml))
          .build()
          .unwrap()
    }
    

    and let say one of my YAMLs has such:

    debug: false
    

    and another:

    debug: true
    

    then that new method "dump_meta" could print something like this:

    debug: false <= taken from service.yml
    debug: true <= taken as override from service-dev.yml and effective
    

    As I'm yet new to Rust - this is just proposal at this point from my side, which I could try to implement one day if no volunteers.

    opened by andrejusc 3
  • Give field in struct another valid name when parsing

    Give field in struct another valid name when parsing

    I want to use this crate to parse a toml config file. This is part of my current code:

    #[derive(Deserialize)]
    pub struct ConfigRawFile {
    	command: Option<String>,
    	interval: Option<f64>,
    	fg: Option<String>,
    	bg: Option<String>,
    	fg_cursor: Option<String>,
    	bg_cursor: Option<String>,
    	bg_selected: Option<String>,
    	bold: Option<bool>,
    	bold_cursor: Option<bool>,
    	keybindings: Option<KeybindingsRaw>,
    }
    
    fn parse_toml(config_file: &str) -> Result<ConfigRawFile, config::ConfigError> {
    	config::Config::builder()
    		.add_source(config::File::with_name(config_file))
    		.build()?
    		.try_deserialize()
    }
    

    However, I want to give e.g. bg_cursor a different name that should be read from in the toml file. I would like the toml file to specify "bg+" (which I can't use as a variable name in rust due to the +), and then read that into bg_cursor. Is there an annotation I can use for this (similar to #[arg(long = "bg+", value_name = "COLOR")] in clap)? This would be very useful! Thanks!

    opened by fritzrehde 4
  • Cannot get config-rs to read env variables

    Cannot get config-rs to read env variables

    Getting the following error when trying to get an environmental variable from config-rs:

    thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: configuration property "DEV_SERVER_ADDRESS" not found', src/app/config.rs:14:27 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace


    use config::Config;
    use lazy_static;
    
    lazy_static! {
        #[derive(Debug)]
        pub static ref CONFIG: Config = Config::builder()
            .add_source(config::Environment::with_prefix("APP_NAME").separator("_"))
            .add_source(config::File::with_name("AppName"))
            .build()
            .unwrap();
    }
    
    pub fn get<'a, T: serde::Deserialize<'a>>(key: &str) -> T {
        CONFIG.get::<T>(&key).unwrap()
    }
    

    ENV variable:

    export APP_NAME_DEV_SERVER_ADDRESS="testtt dev addr"
    

    Trying to get the variable in main:

    #[actix_web::main]
    async fn main() -> result::Result<(), io::Error> {
    
        let dev_server_address: String = app::config::get("DEV_SERVER_ADDRESS");
        println!("DEV_SERVER_ADDRESS: {}", dev_server_address);
    ...
    

    What am I doing wrong?

    opened by brsnik 14
  • Example: Best practice for load/save

    Example: Best practice for load/save

    It could be an idea to have a best practice example of loading a configuration from a file, changing a value, and then saving it out in say a .toml format.

    opened by jesperpedersen 0
  • Make path::Expression module public

    Make path::Expression module public

    I'm working on feature control library and would like to take dependency on Value and path::Expression. Unfortunately, path::Expression is not public module. It is useful even outside the context of config-rs. Can you make it public in the next release?

    opened by hkr1990 1
Owner
Ryan Leckey
Ryan Leckey
Kusion Configuration Language (KCL) is an open source configuration language mainly used in Kusion Stack

Kusion Configuration Language (KCL) is an open source configuration language mainly used in Kusion Stack. KCL is a statically typed language for configuration and policy scenarios, based on concepts such as declarative and Object-Oriented Programming (OOP) paradigms.

KusionStack 264 Dec 30, 2022
cfg-rs: A Configuration Library for Rust Applications

cfg-rs: A Configuration Library for Rust Applications Major Features One method to get all config objects, see get. Automatic derive config object, se

Daniel YU 20 Dec 16, 2022
Just-config is a configuration library for rust

Config Library for Rust Just-config is a configuration library for rust. It strives for the old Unix mantra "Do one thing and to it well".

FlashSystems 7 Apr 15, 2022
A Rust library for processing application configuration easily

Configure me A Rust library for processing application configuration easily About This crate aims to help with reading configuration of application fr

Martin Habovštiak 48 Dec 18, 2022
Zap - A simple cross-platform configuration management and orchestration tool

Zap - A simple cross-platform orchestration and configuration management tool. The main goal for Zap is to a simple mechanism for managing groups of com

R. Tyler Croy 50 Oct 29, 2022
Uclicious is a flexible reduced boilerplate configuration framework.

Uclicious What is Uclicious Usage Raw API Derive-driven Validators Type Mapping Supported attributes (#[ucl(..)]) Structure level Field level Addition

Andrey Cherkashin 14 Aug 12, 2022
🌽 A simple and pain-free configuration language.

?? Corn A simple and pain-free configuration language. Corn has been designed using inspiration from JSON and Nix to produce a language that's easy an

Jake Stanger 3 Nov 28, 2022
Build a config structure from environment variables in Rust without boilerplate

Yasec Yet another stupid environment config (YASEC) creates settings from environment variables. (Envconig-rs fork) Features Nested configuration stru

null 4 Dec 28, 2021
Your next config manager, written in rust

confy Your next config manager, written in rust Based on uncomfyhalomacro/hmph but written for .ini files instead of json :) Getting started Take a lo

Krishna Ramasimha 2 Nov 3, 2021
An easy to configure wrapper for Rust's clippy

An easy to configure wrapper for Rust's clippy

Eric Seppanen 46 Dec 19, 2022
Easy c̵̰͠r̵̛̠ö̴̪s̶̩̒s̵̭̀-t̶̲͝h̶̯̚r̵̺͐e̷̖̽ḁ̴̍d̶̖̔ ȓ̵͙ė̶͎ḟ̴͙e̸̖͛r̶̖͗ë̶̱́ṉ̵̒ĉ̷̥e̷͚̍ s̷̹͌h̷̲̉a̵̭͋r̷̫̊ḭ̵̊n̷̬͂g̵̦̃ f̶̻̊ơ̵̜ṟ̸̈́ R̵̞̋ù̵̺s̷̖̅ţ̸͗!̸̼͋

Rust S̵̓i̸̓n̵̉ I̴n̴f̶e̸r̵n̷a̴l mutability! Howdy, friendly Rust developer! Ever had a value get m̵̯̅ð̶͊v̴̮̾ê̴̼͘d away right under your nose just when

null 294 Dec 23, 2022
A rust layered configuration loader with zero-boilerplate configuration management.

salak A layered configuration loader with zero-boilerplate configuration management. About Features Placeholder Key Convension Cargo Features Default

Daniel YU 28 Sep 20, 2022
Extreme fast factor expression & computation library for quantitative trading in Python.

Extreme fast factor expression & computation library for quantitative trading in Python.

Weiyuan Wu 22 Dec 8, 2022
A strong, compile-time enforced authorization framework for rust applications.

DACquiri A compile-time enforced authorization framework for Rust applications. Authorization In typical applications, authorization checks are perfor

resync 247 Dec 20, 2022
Guarding 是一个用于 Java、JavaScript、Rust、Golang 等语言的架构守护工具。借助于易于理解的 DSL,来编写守护规则。Guarding is a guardians for code, architecture, layered.

Guarding Guarding is a guardians for code, architecture, layered. Using git hooks and DSL for design guard rules. Usage install cargo install guarding

Inherd OS Team (硬核开源小组) 47 Dec 5, 2022
Precio is a Rust library that implements the Precio protocol for computing private layered histograms and sums.

Overview of Precio Precio is a Rust implementation of the protocol described in eprint.iacr.org/2021/1490. The goal of the protocol is to enable an an

Microsoft 9 Aug 16, 2023
Layered bitset implementation

Layered bitsets This crates contains implementation of bitsets with layered structure, allowing fast operations that benifit from skipping large empty

Zakarum 4 Apr 16, 2022
A systemd-boot configuration and boot entry configuration parser library

A systemd-boot configuration and boot entry configuration parser library

Kaiyang Wu 2 May 22, 2022
Kusion Configuration Language (KCL) is an open source configuration language mainly used in Kusion Stack

Kusion Configuration Language (KCL) is an open source configuration language mainly used in Kusion Stack. KCL is a statically typed language for configuration and policy scenarios, based on concepts such as declarative and Object-Oriented Programming (OOP) paradigms.

KusionStack 264 Dec 30, 2022
wireguard tool to manage / generate configuration. Maintain one yaml configuration file to quickly build wireguard network.

wgx wireguard tool to manage / generate configuration. Maintain one yaml configuration file to quickly build wireguard network. Usage wgx --h USAGE:

yinheli 6 Nov 3, 2022