#options

optify

Simplifies getting the right configuration options for a process using pre-loaded configurations from files (JSON, YAML, etc.) to manage options for experiments or flights. This library is mainly made to support building implementations for other languages such as Node.js, Python, and Ruby. It is not meant to be consumed directly yet.

24 releases (4 stable)

new 1.3.0 Jun 4, 2026
1.0.0 Apr 8, 2026
0.21.0 Apr 8, 2026
0.20.5 Dec 10, 2025
0.6.0 Mar 9, 2025

#129 in Configuration

Download history 63/week @ 2026-04-05 52/week @ 2026-04-12 96/week @ 2026-04-19 85/week @ 2026-04-26 61/week @ 2026-05-03 148/week @ 2026-05-10 205/week @ 2026-05-17 144/week @ 2026-05-24 176/week @ 2026-05-31

673 downloads per month
Used in optify-cli

MIT license

135KB
3K SLoC

Optify in Rust

Crates.io docs.rs

The core implementation of Optify in Rust. Simplifies getting the right configuration options for a process using pre-loaded configurations from files (JSON, YAML, etc.) to manage options for experiments or flights.

Usage

Set up your configuration files as explained in the homepage.

Load the configuration directory once when your application starts. Use the enabled features for a request or process to get the merged options for a key:

use optify::provider::OptionsRegistry;
use optify::OptionsProvider;
use serde::Deserialize;

#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
struct MyConfig {
    my_array: Vec<String>,
    my_object: MyObject,
    root_string: String,
}

#[derive(Debug, Deserialize)]
struct MyObject {
    deeper: Deeper,
}

#[derive(Debug, Deserialize)]
struct Deeper {
    #[serde(rename = "new")]
    new_value: String,
}

fn main() -> Result<(), String> {
    let provider = OptionsProvider::build("path/to/configs")?;
    let options = provider.get_options("myConfig", &["feature_A", "feature_B/initial"])?;
    let config: MyConfig = serde_json::from_value(options).map_err(|error| error.to_string())?;

    println!("{}", config.root_string);
    println!("{}", config.my_array.join(", "));
    println!("{}", config.my_object.deeper.new_value);

    Ok(())
}

Use get_all_options when you want the full merged options object instead of one key:

let options = provider.get_all_options(&["feature_A", "feature_B/initial"], None, None)?;

See tests for examples and tests for different implementations of this format for managing options.

How It Works

The config crate (library) is used to help load configuration files. This allows us to load many different types of files, including JSON, JSON5, YAML, and more. We no longer use the config crate to combine configuration files because it was slower to merge them and deserialize the result than our custom merging logic since we know that we want to use serde_json::Values.

We merge configurations starting with the first one given and thus the final feature overrides the previous ones. We may try to optimize further in the future, but this is fine now when there are just a few features or imports and when keys are mostly unique.

Optionally, when working locally, there is support to watch for changes to the configuration files and folders using the notify-debouncer-full crate (library).

Testing

Run:

cargo test

Formatting

To automatically change code, run:

cargo fmt && cargo clippy --fix --allow-dirty --allow-staged

Benchmarking

Run:

cargo build --release
cargo bench

# Run one specific benchmark, example:
cargo bench --bench get_options_benchmark

# Open one of the reports
open target/criterion/*/report/index.html

Publishing

cargo login
cargo publish

Dependencies

~18–33MB
~478K SLoC