SDKs

flagbearer for Rust

The Rust SDK for Flagbearer. Requires Rust 1.85 or later.

Install

cargo add flagbearer

Keys

Use a server key, which starts with fbs_. Server keys are secret: read them from the environment, such as FLAGBEARER_SERVER_KEY, and never put them in browser code or in the repository. Browsers use client keys, which start with fbc_, through @flagbearer/web.

Sync at startup

Create one client per process, when the app starts, and wait for it to sync before accepting requests:

use std::time::Duration;

let flags = flagbearer::Client::new(
    std::env::var("FLAGBEARER_SERVER_KEY")?,
    flagbearer::Options::default(),
)?;

if let Err(error) = flags.sync_timeout(Duration::from_secs(10)) {
    // Keep starting: checks use their defaults, and the SDK retries in the background.
    eprintln!("Initial Flagbearer sync failed: {error}");
}

Check per request

Share the client across requests, for example in an Arc, and pass each request's user explicitly with a default. This axum app syncs once at startup:

use std::sync::Arc;

use axum::{extract::State, routing::get, Router};
use flagbearer::{Client, Options, User};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let flags = Arc::new(Client::new(
        std::env::var("FLAGBEARER_SERVER_KEY")?,
        Options::default(),
    )?);

    let startup = Arc::clone(&flags);
    if let Err(error) = tokio::task::spawn_blocking(move || startup.sync()).await? {
        eprintln!("Initial Flagbearer sync failed: {error}");
    }

    let app = Router::new()
        .route("/search", get(search))
        .with_state(flags);
    let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await?;
    axum::serve(listener, app).await?;
    Ok(())
}

async fn search(State(flags): State<Arc<Client>>) -> &'static str {
    let user = User {
        key: Some("user-1".into()),
        email: Some("ann@example.com".into()),
    };
    if flags.is_enabled("advanced-search", &user, false) {
        "advanced"
    } else {
        "basic"
    }
}

The email is optional. Include it to turn flags on for testers by email. The default is used until the client has synced, and when the flag doesn't exist.

Shut down

Keep the client for the life of the process, not per request. Close it on shutdown:

if let Err(error) = flags.close() {
    eprintln!("Final Flagbearer upload failed: {error}");
}

In async code, close it on a blocking thread. Serverless functions should call flags.flush() at the end of each invocation.