confy: a config file for a Rust CLI in four lines of code
🛋 Zero-boilerplate configuration management in Rust
At a glance
- What is it?
- confy is a Rust library that loads and stores a serde-derived struct as a configuration file in the platform's conventional location, with TOML by default and YAML or RON behind feature flags. Version 2.0 switched to the etcetera crate, which changed where macOS files land.
- Who is it for?
- confy fits a Rust command line tool that needs a config file in the user's home directory and does not want to hand-roll the path resolution or the default-file logic, and that is happy with one format per binary. It does not fit an application that needs several config files merged or several formats at once, since only one of the format features can be enabled at a time.
- Can I use it commercially?
- Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
- Is it still maintained?
- Activity is slowing. The repository last received commits 6 months ago.
- What is it written in?
- Mainly Rust, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
The whole API in one example
confy is described as zero-boilerplate configuration management, with the instruction to focus on storing the right data instead of worrying about how or where to store it. The README's example shows the whole idea in one block.
use serde_derive::{Serialize, Deserialize};
#[derive(Default, Debug, Serialize, Deserialize)]
struct MyConfig {
version: u8,
api_key: String,
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
let cfg: MyConfig = confy::load("my-app-name", None)?;
dbg!(cfg);
Ok(())
}There is no path handling, no directory creation, no default-file writing, no format selection. You derive Serialize and Deserialize on your struct, you call `confy::load` with a name and an optional second argument, and you get a struct back. If the file does not exist, the Default is used, which is why the derive includes Default.
The `None` second argument is the optional parameter added in version 0.5.0, which exists for the case where you need multiple configurations or a different filename. The `load` and `store` pair are the base functions of the library, and `store` writes the struct back out in the same place.
The dependency list in the manifest shows how small this is. `serde` for the derive, `etcetera` for the platform paths, `thiserror` for the error type, `lazy_static` for a global, and then the three optional format crates. There is no async runtime, no async file IO and no configuration framework. The crate is edition 2024 and the manifest version is 2.0.0.
The project sits in the rust-cli organisation, and the README points to a Rust CLI book for guidance on adding context to error messages, so confy is treated as one component of a set of small CLI-oriented crates rather than a standalone framework.
One format at a time, chosen by feature flag
confy can be used with either TOML, YAML or RON files, and the constraint is the part worth internalising.
TOML is the default language used with confy, and the other languages are enabled with feature flags. The important rule is that you can only use one of these features at a time, so to use either of the optional features you have to disable default features.
For YAML, you need the `yaml_conf` feature enabled and both `toml_conf` and `ron_conf` disabled:
[dependencies.confy]
features = ["yaml_conf"]
default-features = falseFor RON the pattern is the same, with `ron_conf` enabled and `toml_conf` and `yaml_conf` disabled:
[dependencies.confy]
features = ["ron_conf"]
default-features = falseThe manifest's feature list shows the full set, and it contains one entry the README does not mention. The default is `toml_conf`, there is `toml_conf`, `basic_toml_conf`, `yaml_conf` and `ron_conf`. The `basic_toml_conf` feature pulls in the `basic-toml` crate rather than the full `toml` crate, which is a lighter TOML implementation for the case where you want the format without the full parser.
The restriction to one format is a consequence of the crate design rather than a technical impossibility, and it is worth knowing before you write a tool that might want to read both a TOML and a YAML file. The pragmatic answer is to pick the format your users already have, since the default is TOML and it is the format Rust projects tend to use already.
Where the file actually lands
confy uses the etcetera crate to store configuration files, and the location depends on the strategy used, either App Strategy or Native Strategy. You can change the strategy with the built-in `change_config_strategy` function.
The App Strategy is the default in version 2.0.0 and later, and it uses the XDG format on both Linux and macOS systems. The paths are `$XDG_CONFIG_HOME`/`<project_path>` or `$HOME`/.config/`<project_path>` on Linux, `$HOME`/.config/`<project_path>` on macOS, and `{FOLDERID_RoamingAppData}`/`<project_path>`/config on Windows. The `<project_path>` is `$MY_APP_NAME`.
The Native Strategy is the older arrangement, kept for backwards compatibility and for GUI applications on macOS which expect that format. On macOS it puts the file at `$HOME`/Library/Application Support/`<project_path>`, and on Linux and Windows the paths are the same as the app strategy. The difference is the macOS prefix, where the project path becomes `rs.$MY_APP_NAME` on macOS and just `$MY_APP_NAME` elsewhere.
That macOS prefix detail is the thing to know about the 2.0 change. The breaking change section says the project moved from the ProjectDirs crate to etcetera, allowing both XDG and native paths to be used, and that from now on the default will be using XDG directories on macOS. A tool that shipped a config file at `~/Library/Application Support/my-app/` and then upgraded confy to 2.0 will start from defaults, because the file is now expected at `~/.config/my-app/`.
The `rs.` prefix in the native strategy is the Rust CLI convention, so that a Rust program's directory sits alongside the other application directories on macOS rather than in the root of Application Support.
The version history as a compatibility guide
The README keeps a running list of breaking changes, and reading it in order tells you what the library has done to your files over time.
Version 2.0.0 is the etcetera switch described above, with the macOS path change as its consequence.
Version 0.6.0 bumped dependencies that changed the default serialisation and deserialisation behaviour. `serde_yaml` moved from v0.8 to v0.9, which had several breaking changes, especially cases where numbers were previously parsed and now return a String. The `toml` crate moved from v0.5 to v0.8, where the breaking change is to how tuple variants work: serialisation and deserialisation of tuple variants changed from being an array to being a table with the key being the variant name and the value being the array. That is the kind of change that turns a round trip into a diff, and it is the reason to read the notes before bumping.
Version 0.5.0 added the optional parameter to `load` and `store` for multiple configurations or different filenames, and changed the default configuration file name to `default-config` instead of the application's name, with the instruction to put the second argument of `load` and `store` to be the same as the first to keep the previous configuration file. It also made it possible to save the configuration as `toml` or as YAML, with the file extension depending on the format used.
Version 0.4.0 moved the configuration file to the expected place for your system, using the directories crates. Before that version, the configuration file was written in the current directory.
The release tags show v0.6.1 in March 2024, v1.0.0 in May 2025 and v2.0.0 in October 2025, and the last push was on 2026-04-13.
The licence, the example and the maintenance state
This work is triple-licensed under MIT, MIT/X11, or the Apache 2.0 (or any later version), and you may choose any one of the three. The SPDX identifier is `MIT OR X11 OR Apache-2.0+`, and the repository carries a separate LICENSE file for each, so the choice is made at the dependency level rather than being a single fixed set of terms.
The repository is small. There is `src/`, an `examples/` directory with a single `simple.rs`, the three licence files, an `audit.toml` for cargo-audit configuration, a `Cargo.toml` and a README. The `[[example]]` section in the manifest declares the `simple` example by name, and the dev dependencies are `serde_derive` and `tempfile`.
The `audit.toml` is worth a second look for a project with this few dependencies. It is the configuration for cargo-audit, the tool that checks your dependency tree against the RustSec advisory database, and having it in the tree means the security check is part of the project rather than something a user has to remember to run.
On maintenance, the picture is mixed and worth being precise about. The last push was on 2026-04-13, and the newest release tag is v2.0.0 from 2025-10-27. The library is small and the API surface is three functions and a strategy switch, so there is not much to break, but the project is not currently moving quickly, and the 0.6.0 dependency bumps in the list are a reminder of the maintenance that does come with format support.
The Discord badge in the README is where a question about any of this would go.
Editorial conclusion
confy fits a Rust command line tool that needs a config file in the user's home directory and does not want to hand-roll the path resolution or the default-file logic, and that is happy with one format per binary. It does not fit an application that needs several config files merged or several formats at once, since only one of the format features can be enabled at a time. Before adopting it, decide between the app and native strategies, because the 2.0 default moved macOS to XDG paths and any existing file at the old location will not be found.
Frequently asked questions
What is confy?
It is a Rust library for zero-boilerplate configuration management. You derive Serialize and Deserialize on your config struct and call `confy::load("my-app-name", None)`, and the library handles the file location, the format and the default file.
Can confy read YAML or RON files?
Yes, but only one format at a time. TOML is the default via the toml_conf feature, and to use YAML you enable yaml_conf or to use RON you enable ron_conf, in both cases with default-features = false so the other formats are disabled.
Where does confy store the configuration file?
It uses the etcetera crate, and the path depends on the strategy. The default App Strategy uses XDG paths, so $HOME/.config/<project> on Linux and macOS, and the Native Strategy uses the OS convention, with rs.<project> under Library/Application Support on macOS.
What changed in confy 2.0.0?
The project moved from the ProjectDirs crate to etcetera, which allows both XDG and native paths to be used. The visible consequence is that the default now uses XDG directories on macOS, so a config file at the old Application Support location will not be found after the upgrade.
What licence is confy under?
It is triple-licensed under MIT, MIT/X11, or the Apache License 2.0 or any later version, and you may choose any one of the three. The SPDX identifier is MIT OR X11 OR Apache-2.0+.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/rust-cli-confy)Was this useful?