---
title: Cargo features and dependencies
description: The two optional features rtb-config ships, what each one adds to the API and to your dependency graph, and the crate's MSRV and always-on dependencies.
---
# Cargo features and dependencies
`rtb-config` has two Cargo features and **both are off by default**. Everything on
the [API reference](api.md) that is not marked with a feature works with a plain
dependency line.
```toml
[dependencies]
rtb-config = "0.6"
```
## Which feature do I need?
| `hot-reload` | `Config::watch_files`, the `WatchHandle` type, the `rtb_config::watch` module | `notify`, `notify-debouncer-full` | off |
| `mutable` | `Config::schema`, `Config::write` | `schemars`, `serde_json`, `serde_yaml`, `toml` | off |
```toml
# a long-running service that reloads on file change
rtb-config = { version = "0.6", features = ["hot-reload"] }
# a CLI with `config set` / `config schema` subcommands
rtb-config = { version = "0.6", features = ["mutable"] }
# both
rtb-config = { version = "0.6", features = ["hot-reload", "mutable"] }
```
The features are independent — neither implies the other, and there is no
combination of the two that is unsupported.
## What if I call a feature-gated method without the feature?
It does not exist, so the build fails at compile time with `no method named
watch_files found` or `no function or associated item named schema found`. There is
no runtime fallback and nothing silently degrades.
If a method you expected is missing and the feature *is* enabled, check the trait
bounds — `write` and `schema` also need `C: Serialize + JsonSchema`. See
[which trait bounds does my config struct need](api.md#which-trait-bounds-does-my-config-struct-need).
## Why is hot-reload not on by default?
A file watcher costs an OS watch handle, a background thread and two more crates, and
most consumers of a config crate are short-lived CLI invocations that read config once
and exit. Making the watcher opt-in keeps that common case cheap. The same reasoning
applies to `mutable`: a tool that never writes config back should not carry a YAML and
a TOML serialiser to do it.
## What does rtb-config depend on unconditionally?
| `figment` | The layering and merge engine, with its `toml`, `yaml`, `json` and `env` features |
| `serde` | The `Deserialize` derive your config struct uses |
| `arc-swap` | The atomic pointer swap behind `get` and `reload` |
| `tokio` | `tokio::sync::watch` powers `Config::subscribe` |
| `thiserror` | The `ConfigError` derive |
| `miette` | Diagnostic codes and help text on every error variant |
Two of those are worth calling out because they are larger than they need to be for
what the crate uses:
- **`tokio` is not optional and is declared with `features = ["full"]`**, even though
only `tokio::sync::watch` is used. If you are counting build time or binary size,
that is where it goes.
- **`figment` is built with the `toml` and `json` features**, but only its YAML and
environment providers are wired up. `ConfigBuilder::user_file` always parses YAML —
see [can I use a TOML or JSON config file](../explanation/limitations.md#can-i-use-a-toml-or-json-config-file).
## Do I need a tokio runtime?
Only to await changes. `build`, `get`, `reload` and `write` are ordinary synchronous
calls and work in a program with no async runtime at all. `Config::subscribe` returns
a `tokio::sync::watch::Receiver`, and `rx.borrow()` is synchronous too — it is
`rx.changed().await` that needs an async context.
`watch_files` runs on a plain OS thread, not a tokio task, so the watcher itself does
not need a runtime either.
## What Rust version does this need?
| Edition | 2021 |
| MSRV (`rust-version`) | 1.82 |
| Toolchain used in CI | pinned exactly in `rust-toolchain.toml` |
CI pins one exact stable rather than tracking the floating `stable` channel, so a new
rustc release cannot change the build without a reviewed toolchain bump.
The crate is `#![forbid(unsafe_code)]` — not `deny`, which a module can locally
override. There is no `unsafe` block anywhere in the shipped code.
## Next
- [API reference](api.md) — the full surface, feature by feature
- [Reload configuration at runtime](../how-to/reload-configuration-at-runtime.md) — using `hot-reload`
- [Write config back and export its schema](../how-to/write-config-and-export-a-schema.md) — using `mutable`