28 releases

0.9.2 May 26, 2024
0.9.0 Oct 25, 2023
0.7.3 Jul 18, 2023
0.5.0 Mar 17, 2023
0.1.0 Dec 25, 2022

#152 in Configuration

MIT license



Asynchronous Centralized Configuration Management for Rust

config-it is an asynchronous library that offers centralized configuration management for Rust applications. Here are its key features:

  • Define custom configuration templates using structs.
  • Create multiple instances with different paths based on a single template.
  • Receive notifications when your instance is updated.
  • Use serde compatible archive formats to archive your data in your preferred way.
  • Manage property-wise dirty flags for precise, responsive updates to your system.

As I'm not very good at writing English sentences, got some help from AI to write this README file. Thanks, robot!



A crate for asynchronous centralized configuration management.


You can define 'Template' which defines set of grouped properties, which should be updated at once. Only config_it decorated properties will be counted as part of given group and will be managed.

Template must implement Clone trait.

You should create Storage to create config group instances(Group<T:Template>). Storage is the primary actor for centralized configuration management. Config groups can be instantiated based on storage instance.

Any property implements serde::Serialize, serde::DeserializeOwned can be used as configuration property.


Any field decorated with attribute #[config_it] or #[config] will be treated as configuration property. You can specify additional constraints for the property by adding additional attributes inside parenthesis.

  • default = <value>
    • Specify default value for the property. as the expression is converted into field type using .try_into().unwrap() expression, you should specify un-fallible expression here. This is to support convenient value elevation from &str to String, or similar owning conversions.
  • default_expr = "<expr>"
    • Specify complicated value expression here. To specify string literal here, you have to escape double quotes(") with backslash(\). As this attribute converts given expression into token tree directly, you can write any valid rust expression here.
  • rename = "<alias>"
    • Specify alias name for the property. This is useful when you want to use different name for the property in config file, but want to use original name in code.
  • one_of = [<value>, <value>, ...]
    • Specify set of allowed values for the property. This is useful when you want to restrict the value of the property to specific set of values. You can also specify default value as one of the allowed values.
    • Default value can be out of the allowed set, and can be excluded from the allowed set. In this case, setting value back to default value will not be allowed.
  • min = <value>, max=<value>
    • Constrain the value of the property to be within given range. Any type which implements Ord can have min/max constraints.
  • env = "<env_var>" or env_once = "<env_var>"
    • Specify environment variable name to import value from. If the environment variable is not set, the default value will be used. TryParse trait is used to convert environment variable value into property type.
    • env_once is only evaluated once lazily and reuse cached value after creation.
  • no_import
    • Do not update value from imported archive. This is useful when mixed with env flag, which will keep its value as imported environment variable even after the archive is imported.
  • no_export
    • Do not export value to archive.
  • transient
    • Value won't be archived, and won't be imported from archive.
  • hidden
    • Hints to monitoring system that this property should not be visible.
  • no_notify

Non-default values

A storage template may consist of multiple non-config field. Since Template macro does not require Default trait to be implemented, it will report error if the non-config type does not provide type-level default implementation.

#[derive(config_it::Template, Clone)]
struct Config {
    #[config(default = 154)]
    pub any_number: i32,

    // This is just okay.
    pub non_config_with_default: usize,

    pub non_config_number: std::num::NonZeroUsize,
 // ^^^ the trait `Default` is not implemented for `NonZeroUsize`

In this case, you can specify non-default value for the field via non_config_default_expr attribute. This attribute accepts string literal, which will be parsed as rust expression.

#[derive(config_it::Template, Clone)]
struct Config {
    #[config(default = 154)]
    pub any_number: i32,

    #[non_config_default_expr = r#"1.try_into().unwrap()"#]
    pub non_config_number: std::num::NonZeroUsize,


~120K SLoC