Expand description
Confique is a type-safe, layered, light-weight, serde-based configuration library.
The core of the library is the Config trait and its derive-macro.
You define your configuration value as one or more structs, each of which has
to #[derive(Config)]. Then you can use different ways of loading an instance
of your root configuration struct.
§How to use
Add confique as dependency to your Cargo.toml and remember to enable the
crate features for file formats you are interested in. For example:
cargo add confique --features=toml.
§Defining your configuration with structs
First, define some structs that describe all your configuration values. Use
the types you want to use in your code. For example, if you have a port
config and your code needs that value, it should be of type u16,
and not Option<u16> or String. That way, the code using that value is
cleanest.
Small example:
use confique::Config;
#[derive(Config)]
struct Conf {
// A required value. Since it's not `Option<_>`, it has to be specified when
// loading the configuration, or else loading returns an error.
username: String,
// An optional value.
welcome_message: Option<String>,
// A required value with default value. If no other value is specified
// (e.g. in a config file), the default value is used.
#[config(default = 8080)]
port: u16,
}As your application grows, oftentimes you want to split the configuration
into multiple structs. This has the added benefit that your config files
are somewhat structured or have sections. You can do that by including
other types that implement Config with #[config(nested)].
use std::path::PathBuf;
use confique::Config;
#[derive(Config)]
struct Conf {
username: String,
#[config(nested)]
log: LogConf,
#[config(nested)]
db: DbConf,
}
#[derive(Config)]
struct LogConf {
#[config(default = true)]
stdout: bool,
file: Option<PathBuf>,
}
#[derive(Config)]
struct DbConf {
// ...
}You can also attach some other attributes to fields. For example, with
#[config(env = "KEY")], you can load a value from an environment variable.
With #[config(validate = ...)] you can add validation checks. For more
information, see the docs for the derive macro.
Note: if a field hast #[config(nested)], its type must implement
Config, otherwise it must implement serde::Deserialize.
§Loading the configuration
Here, you have multiple options. Most of the time, you can probably use the
provided high-level methods of Config, like Config::from_file and
Config::builder.
use confique::Config;
// Load from a single file only.
let config = Conf::from_file("config.toml")?;
// Or load from multiple sources (higher priority sources are listed first).
let config = Conf::builder()
.env()
.file("config.toml")
.file("/etc/myapp/config.toml")
.load()?;But you can also assemble your configuration yourself. That’s what
the layer types are for (i.e. Config::Layer). These implement
serde::Deserialize and can thus be loaded from a vast number of sources.
One of those sources is the built-in File which gives you a bit more
control when loading configuration from files. And you can always simply
create an instance of the layer type by writing all values in Rust code
with struct initializer syntax!
Once you have all your layers collected, you have to combine
them via Layer::with_fallback and convert them to the actual config
type via Config::from_layer. And you probably also want to use
Layer::default_values as the last layer.
use confique::{Config, File, FileFormat, Layer};
#[derive(Config)]
struct Conf {
foo: f32,
}
type ConfLayer = <Conf as Config>::Layer;
let from_file: ConfLayer = File::with_format("/etc/foo/config", FileFormat::Toml)
.required()
.load()?;
let manual = ConfLayer {
// Remember: all fields in the layer types are `Option`s!
foo: Some(3.14),
};
let defaults = ConfLayer::default_values();
let merged = from_file.with_fallback(manual).with_fallback(defaults);
let config = Conf::from_layer(merged)?;§Using your configuration
Well, this is the simple part: the loaded configuration is just an instance of your struct. And you already know how to access fields of structs!
§Other notes
- To use CLI as a layer when loading your configuration, see the
clapexample!
§Cargo features
This crate has a Cargo feature for each supported file format. These are not enabled by default, so you have to specify which file formats you are interested in.
confique = { version = "...", features = ["toml"] }All crate features:
toml: enables TOML support and adds thetomldependency.yaml: enables YAML support and adds theserde_yamldependency.json5: enables JSON5 support and adds thejson5dependency.
Re-exports§
pub use serde;
Modules§
- env
- Deserialize values from environment variables.
- json5
- JSON5 specific features. This module only exists if the Cargo feature
json5is enabled. - meta
- Types for
Config::META. Represent information about a configuration type. - toml
- TOML specific features. This module only exists if the Cargo feature
tomlis enabled. - yaml
- YAML specific features. This module only exists if the Cargo feature
yamlis enabled.
Structs§
- Builder
- Convenience builder to configure, load and merge multiple configuration sources.
- Error
- Type describing all errors that can occur in this library.
- File
- A file as source for configuration.
- Format
Options - General (non format-dependent) template-formatting options.
Enums§
- File
Format - All file formats supported by confique.
Traits§
- Config
- A configuration object that can be deserialized in layers via
serde. - Layer
- A configuration layer: all fields are optional. Can be directly deserialized
via
serde.