The following illustrates some real-world examples of features in action.
Minimizing build times and file sizes
Some packages use features so that if the features are not enabled, it reduces the size of the crate and reduces compile time. Some examples are:
synis a popular crate for parsing Rust code. Since it is so popular, it is helpful to reduce compile times since it affects so many projects. It has a clearly documented list of features which can be used to minimize the amount of code it contains.
regexhas a several features that are well documented. Cutting out Unicode support can reduce the resulting file size as it can remove some large tables.
winapihas a large number of features that limit which Windows API bindings it supports.
web-sysis another example similar to
winapithat provides a huge surface area of API bindings that are limited by using features.
serde_json package has a
which changes the behavior of JSON maps to preserve the
order that keys are inserted. Notice that it enables an optional dependency
indexmap to implement the new behavior.
When changing behavior like this, be careful to make sure the changes are SemVer compatible. That is, enabling the feature should not break code that usually builds with the feature off.
Some packages want to support both
std environments. This is
useful for supporting embedded and resource-constrained platforms, but still
allowing extended capabilities for platforms that support the full standard
wasm-bindgen package defines a
std feature that
is enabled by default. At the top of the library, it
unconditionally enables the
no_std attribute. This
std and the
std prelude are not automatically in scope.
Then, in various places in the code (example1,
example2), it uses
#[cfg(feature = "std")] attributes
to conditionally enable extra functionality that requires
Re-exporting dependency features
It can be convenient to re-export the features from a dependency. This allows
the user depending on the crate to control those features without needing to
specify those dependencies directly. For example,
regex re-exports the
features from the
package. Users of
regex don’t need to know about the
but they can still access the features it contains.
Vendoring of C libraries
Some packages provide bindings to common C libraries (sometimes referred to as
“sys” crates). Sometimes these packages give you the choice to use the
C library installed on the system, or to build it from source. For example,
openssl package has a
vendored feature which
enables the corresponding
vendored feature of
openssl-sys build script has some conditional logic which
causes it to build from a local copy of the OpenSSL source code instead of
using the version from the system.
curl-sys package is another example where the
feature causes it to build libcurl from source. Notice that
it also has a
force-system-lib-on-osx feature which forces
it to use the system libcurl, overriding the
Some packages may have mutually-exclusive features. One option to handle this
is to prefer one feature over another. The
log package is an example. It
has several features for choosing the maximum logging level at
compile-time described here. It uses
cfg-if to choose a
precedence. If multiple features are enabled, the higher “max”
levels will be preferred over the lower levels.
Proc-macro companion package
Some packages have a proc-macro that is intimately tied with it. However, not all users will need to use the proc-macro. By making the proc-macro an optional-dependency, this allows you to conveniently choose whether or not it is included. This is helpful, because sometimes the proc-macro version must stay in sync with the parent package, and you don’t want to force the users to have to specify both dependencies and keep them in sync.
An example is
serde which has a
derive feature which
serde_derive proc-macro. The
serde_derive crate is very
tightly tied to
serde, so it uses an equals version
requirement to ensure they stay in sync.
Some packages want to experiment with APIs or language features that are only
available on the Rust nightly channel. However, they may not want to require
their users to also use the nightly channel. An example is
which has a
nightly feature which enables an
extended API that uses the
Unsize marker trait that
is only available on the nightly channel at the time of this writing.
Note that at the root of the crate it uses
cfg_attr to enable the nightly
feature. Keep in mind that the
is unrelated to Cargo features, and is used to opt-in to experimental language
simd_support feature of the
rand package is another example,
which relies on a dependency that only builds on the nightly channel.
Some packages have new functionality that they may want to experiment with,
without having to commit to the stability of those APIs. The features are
usually documented that they are experimental, and thus may change or break in
the future, even during a minor release. An example is the
package, which has an
unstable feature, which gates
new APIs that people can opt-in to using, but may not be
completely ready to be relied upon.