Note
This repo was originally developed by the community and later adopted by GrowthBook.
The official GrowthBook SDK for Rust. This crate provides an easy way to integrate feature flagging and experimentation into your Rust applications.
Add this to your Cargo.toml:
[dependencies]
growthbook-rust = "0.1.0"Use the GrowthBookClientBuilder to create a client instance. This supports auto-refreshing features, caching, and callbacks.
use growthbook_rust::client::GrowthBookClientBuilder;
use std::time::Duration;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let client = GrowthBookClientBuilder::new()
.api_url("https://cdn.growthbook.io".to_string())
.client_key("sdk-key".to_string())
.ttl(Duration::from_secs(60)) // Cache TTL
.auto_refresh(true) // Enable background updates
.refresh_interval(Duration::from_secs(30))
.build()
.await?;
Ok(())
}You can check if a feature is enabled or get its value.
// Simple check
if client.is_on("my-feature", None) {
println!("Feature is enabled!");
}
// Get typed value
let value = client.feature_result("my-config", None).value_as::<String>()?;You can set global attributes that apply to all evaluations, and override them per-check.
use std::collections::HashMap;
use growthbook_rust::model_public::{GrowthBookAttribute, GrowthBookAttributeValue};
// Global attributes
let mut global_attrs = HashMap::new();
global_attrs.insert("tenantId".to_string(), GrowthBookAttributeValue::String("123".to_string()));
let client = GrowthBookClientBuilder::new()
.api_url(api_url)
.client_key(sdk_key)
.attributes(global_attrs)
.build()
.await?;
// Per-check attributes (merged with global)
let mut user_attrs = Vec::new();
user_attrs.push(GrowthBookAttribute::new("userId".to_string(), GrowthBookAttributeValue::String("456".to_string())));
if client.is_on("my-feature", Some(user_attrs)) {
// ...
}You can subscribe to events for tracking and analytics.
let client = GrowthBookClientBuilder::new()
// ...
.on_feature_usage(Box::new(|key, result| {
println!("Feature '{}' evaluated: {:?}", key, result.value);
}))
.on_experiment_viewed(Box::new(|experiment_result| {
// Track experiment impression
println!("Experiment viewed: {}", experiment_result.key);
}))
.build()
.await?;The SDK can also be configured via environment variables if not explicitly set in the builder:
| Env Var | Description |
|---|---|
| GB_HTTP_CLIENT_TIMEOUT | Timeout for HTTP requests. Default: 10s |
| GB_UPDATE_INTERVAL | Interval for auto-refresh (if enabled). Default: 60s |
| GB_URL | GrowthBook API URL |
| GB_SDK_KEY | GrowthBook SDK Key |
The SDK supports automated feature updates via a background task. This is enabled by default when using auto_refresh(true) in the builder.
- Caching: Features are cached in memory by default. You can configure the TTL using
.ttl(Duration::from_secs(60)). - Background Sync: When
auto_refreshis enabled, a background task periodically fetches features from the API and updates the cache. - On Refresh Callback: You can listen for updates using
.add_on_refresh(...).
If you prefer to manage feature updates manually or want to start with a specific set of features (e.g., from a file or another source), you can disable auto-refresh and provide initial features.
use serde_json::json;
let features_json = json!({
"my-feature": {
"defaultValue": true
}
});
let client = GrowthBookClientBuilder::new()
.api_url(api_url)
.client_key(sdk_key)
.auto_refresh(false) // Disable background sync
.features_json(features_json)? // Set features manually
.build()
.await?;
// You can manually refresh features later
client.refresh().await;If you are using encrypted features, you can provide the decryption key to the builder.
let client = GrowthBookClientBuilder::new()
.api_url(api_url)
.client_key(sdk_key)
.decryption_key("your-decryption-key".to_string())
.build()
.await?;The SDK supports Sticky Bucketing to ensure users persist in their assigned variations, even if the user session changes or targeting conditions update.
For simple applications where persistence across restarts is not required (or for testing), you can use the built-in InMemoryStickyBucketService.
use std::sync::Arc;
use growthbook_rust::sticky_bucket::InMemoryStickyBucketService;
let sticky_service = Arc::new(InMemoryStickyBucketService::new());
let client = GrowthBookClientBuilder::new()
.api_url(api_url)
.client_key(sdk_key)
.sticky_bucket_service(sticky_service)
.build()
.await?;For production use cases requiring durable storage (Redis, Database, LocalStorage, etc.), you should implement the StickyBucketService trait.
use std::collections::HashMap;
use growthbook_rust::sticky_bucket::StickyBucketService;
use growthbook_rust::model_public::GrowthBookAttribute;
#[derive(Debug)]
pub struct MyRedisStickyBucketService {
// ... connection pool etc.
}
impl StickyBucketService for MyRedisStickyBucketService {
fn get_assignments(&self, attribute_name: &str, attribute_value: &str) -> Option<HashMap<String, String>> {
// Fetch from Redis usually returning Key (experiment_key) -> Value (variation_key)
// ...
None
}
fn save_assignments(&self, attribute_name: &str, attribute_value: &str, assignments: HashMap<String, String>) {
// Write to Redis
// ...
}
fn get_all_assignments(&self, attributes: &HashMap<String, GrowthBookAttribute>) -> HashMap<String, String> {
// Batch fetch all assignments for the given user attributes
HashMap::new()
}
}