Conditional Compilation in Rust with Feature Flags

Rust feature flag

I was checking out the OpenObserve — an open-source observability tool which you can self-host or use their cloud offering which offers free, standard and enterprise tier to choose from.

Written completely in rust so I thought of checking the codebase on Github to get myself more aquatinted with rust language. While doing so I found a #[cfg(feature = "enterprise")] being used in many places.

Looking at it, one can tell that any function or block decorated with this attribute is conditional, available only if the feature is enabled. But does this happen at compile time or runtime? If it’s compile time, the code will be compiled into the binary solely when the feature is turned on.

To test this and to gain more understanding on this, I created a rust application where I added features section in the cargo.toml file and added two features opensource and enterprise Kind of similar to the offering of OpenObserve. Here is my final cargo.toml file.

[package]
name = "cfgfeature"
version = "0.1.0"
edition = "2024"

[features]
community = []
enterprise = []

I updated my main.rs to this. I kept the hello world in the end.

fn main() {
   #[cfg(feature = "enterprise")]
   enterprise_feature();

   println!("Welcome to the app!");
}

#[cfg(feature = "enterprise")]
fn enterprise_feature() {
    println!("Enterprise feature activated!");
}

If I use just the cargo run command without specifying the --features flag, you will see the output Welcome to the app! which is expected. But the other function call like enterprise_feature was not even considered for execution. This is because of the #cfg[(feature)] attribute in Rust which is used to conditionally compile code only when the enterprise feature is enabled in the crate and passed as a parameter with the --features flag while building or running the program.

To make a binary which has the enterprise feature enabled, I can re-run the same command but this time, I will use --features flag.

$ cargo run --features enterprise

Now you we can see the output from our enterprise_feature function as well.

$ cargo run --features enterprise
   Compiling cfgfeature v0.1.0 (F:\Code\rust\cfgfeature)
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.31s
     Running `target\debug\cfgfeature.exe`
Enterprise feature activated!
Welcome to the app!

When the enterprise feature is not enabled, any code marked with #[cfg(feature = "enterprise")] is completely excluded from compilation. That means:

  • The enterprise_feature function won’t be compiled.
  • It won’t exist in the final binary.
  • It won’t consume any space or resources.
  • You can’t call it unless the feature is enabled — doing so would result in a compile-time error.

This is one of Rust’s powerful mechanisms for feature gating, allowing you to build modular, efficient binaries tailored to specific use cases or environments.

Let’s modify the above code a bit and look at some other ways of using this. Notice how I am marking a println! macro with #[cfg(not(feature = "enterprise"))] This will print the lineEnterprise features are not enabled if I do not compile the code with --features enterprise flag. This line will not be printed if you pass the --features enterprise flag.

fn main() {
    println!("Welcome to the app!");

    #[cfg(feature = "enterprise")]
    enterprise_feature();

    #[cfg(not(feature = "enterprise"))]
    println!("Enterprise features are not enabled.");
}

#[cfg(feature = "enterprise")]
fn enterprise_feature() {
    println!("Enterprise feature is enabled!");
}

Running the above program with cargo run results in this output —

$ cargo run
   Compiling cfgfeature v0.1.0 (F:\Code\rust\cfgfeature)
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.34s
     Running `target\debug\cfgfeature.exe`
Welcome to the app!
Enterprise features are not enabled.

Here is a final example I would like to share. Consider the below code where I have two features enterprise and community and two functions enterprise_feature and community_feature marked with them respectively. But the main eye-catcher in code below are 3 different main functions.

#[cfg(feature = "enterprise")]
fn enterprise_feature() {
    println!("Enterprise feature activated!");
}

#[cfg(feature = "community")]
fn community_feature() {
    println!("Community feature activated!");
}

#[cfg(feature = "enterprise")]
fn main() {
    enterprise_feature();
}

#[cfg(feature = "community")]
fn main() {
    community_feature();
}

#[cfg(not(any(feature = "enterprise", feature = "community")))]
fn main() {
    println!("Not using enterprise or community feature.");
}

This code uses conditional compilation to define different main functions based on enabled feature flags:

  • If the enterprise feature is enabled, the main function calls enterprise_feature().
  • If the community feature is enabled, the main function calls community_feature().
  • If neither enterprise nor community features are enabled—i.e., the program is built without the --features flag—the fallback main function runs, printing a default message.

Here is the output of the above program if I try to run it without any feature flag —

$ cargo run
   Compiling cfgfeature v0.1.0 (F:\Code\rust\cfgfeature)
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.54s
     Running `target\debug\cfgfeature.exe`
Not using enterprise or community feature.

Output of the above program when I run it using the --features enterprise flag —

$ cargo run --features enterprise
   Compiling cfgfeature v0.1.0 (F:\Code\rust\cfgfeature)
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.35s
     Running `target\debug\cfgfeature.exe`
Enterprise feature activated!

Here are other logical combinations that you can use —

  • Only if enterprise is enabled — #[cfg(feature = "enterprise")]
  • Only if both enterprise and community are enabled — #[cfg(all(feature = "enterprise", feature = "community"))]
  • Only if exactly one of them is enabled — #[cfg(any(feature = "enterprise", feature = "community"))]
  • Only if neither is enabled — #[cfg(not(any(feature = "enterprise", feature = "community")))]

You can also use this with modules and crates to conditionally compile them based on feature flags. Here is an example.

#[cfg(not(feature = "enterprise"))]
pub mod basic_features;

#[cfg(feature = "enterprise")]
pub mod enterprise_features;

This ensures that only one of the modules is compiled depending on the feature flag. You can also use it inside the module itself to conditionally compile functions or structs.

You can conditionally include dependencies based on features.

comments powered by Disqus