Toggly Rust SDK
High-performance Rust SDK for Toggly feature flags and experimentation platform.

Features
- Async-first: Built on Tokio for efficient async operations
- Type-safe: Leverages Rust's type system for compile-time safety
- Thread-safe: Safe concurrent access with Arc and DashMap
- Zero-cost abstractions: Minimal overhead with idiomatic Rust patterns
- Framework integrations: Native support for Actix, Axum, and Rocket
- Procedural macros: Declarative feature flag guards
- In-memory caching: Built-in caching with configurable TTL
- WebAssembly support: Works in browser environments
Crates
| Crate |
Description |
Crates.io |
toggly |
Core SDK with minimal dependencies |
 |
toggly-macros |
Procedural macros for feature flags |
 |
toggly-actix |
Actix-web integration |
 |
toggly-axum |
Axum integration |
 |
toggly-rocket |
Rocket integration |
 |
Installation
Add the core crate to your Cargo.toml:
[dependencies]
toggly = "0.1"
For framework integrations:
toggly-actix = "0.1"
toggly-axum = "0.1"
toggly-rocket = "0.1"
toggly-macros = "0.1"
Quick Start
Basic Usage
use toggly::{TogglyClient, EvalContext};
#[tokio::main]
async fn main() -> Result<(), toggly::Error> {
let client = TogglyClient::builder()
.app_key("your-app-key")
.environment("production")
.build()
.await?;
let enabled = client.is_enabled("my-feature", EvalContext::default()).await?;
if enabled {
println!("Feature is enabled!");
}
client.close().await;
Ok(())
}
With User Context
use toggly::{TogglyClient, EvalContext};
use std::collections::HashMap;
async fn check_feature(client: &TogglyClient, user_id: &str) -> bool {
let mut traits = HashMap::new();
traits.insert("plan".to_string(), serde_json::json!("premium"));
traits.insert("country".to_string(), serde_json::json!("US"));
let context = EvalContext::builder()
.identity(user_id)
.groups(vec!["beta-testers".to_string()])
.traits(traits)
.build();
client.is_enabled("premium-feature", context).await.unwrap_or(false)
}
Feature Gates
Evaluate multiple features with AND/OR logic:
use toggly::{TogglyClient, EvalContext, Requirement};
async fn check_access(client: &TogglyClient) -> bool {
client
.evaluate_gate(
&["feature-a", "feature-b"],
Requirement::All,
EvalContext::default(),
false,
)
.await
.unwrap_or(false)
}
Framework Integrations
Actix-web
use actix_web::{web, App, HttpServer, HttpResponse};
use toggly::TogglyClient;
use toggly_actix::{TogglyMiddleware, Feature, FeatureEnabled};
#[actix_web::main]
async fn main() -> std::io::Result<()> {
let client = TogglyClient::builder()
.app_key("your-app-key")
.environment("production")
.build()
.await
.expect("Failed to create client");
HttpServer::new(move || {
App::new()
.app_data(web::Data::new(client.clone()))
.route("/", web::get().to(index))
.route("/beta", web::get().to(beta_handler))
})
.bind("127.0.0.1:8080")?
.run()
.await
}
async fn index(feature: Feature) -> HttpResponse {
if feature.is_enabled("new-homepage").await {
HttpResponse::Ok().body("New Homepage")
} else {
HttpResponse::Ok().body("Classic Homepage")
}
}
async fn beta_handler(_: FeatureEnabled<"beta-features">) -> HttpResponse {
HttpResponse::Ok().body("Beta Content")
}
Axum
use axum::{routing::get, Router, Extension};
use std::sync::Arc;
use toggly::TogglyClient;
use toggly_axum::{Feature, TogglyLayer};
#[tokio::main]
async fn main() {
let client = TogglyClient::builder()
.app_key("your-app-key")
.environment("production")
.build()
.await
.expect("Failed to create client");
let app = Router::new()
.route("/", get(index))
.route("/beta", get(beta_handler).layer(TogglyLayer::require("beta-features")))
.layer(Extension(Arc::new(client)));
let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap();
axum::serve(listener, app).await.unwrap();
}
async fn index(feature: Feature) -> &'static str {
if feature.is_enabled("new-homepage").await {
"New Homepage"
} else {
"Classic Homepage"
}
}
async fn beta_handler() -> &'static str {
"Beta Content"
}
Rocket
use rocket::{get, launch, routes, State};
use toggly::TogglyClient;
use toggly_rocket::{Feature, FeatureEnabled, TogglyFairing};
#[get("/")]
async fn index(feature: Feature<'_>) -> &'static str {
if feature.is_enabled("new-homepage").await {
"New Homepage"
} else {
"Classic Homepage"
}
}
#[get("/beta")]
async fn beta(_: FeatureEnabled<"beta-features">) -> &'static str {
"Beta Content"
}
#[launch]
async fn rocket() -> _ {
rocket::build()
.attach(TogglyFairing::new("your-app-key", "production"))
.mount("/", routes![index, beta])
}
Procedural Macros
Use the toggly-macros crate for declarative feature guards:
use toggly_macros::{feature_flag, FeatureFlags};
#[feature_flag(feature = "premium-feature")]
async fn premium_function() -> String {
"Premium content".to_string()
}
#[derive(FeatureFlags)]
pub enum Features {
#[feature(key = "dark-mode")]
DarkMode,
#[feature(key = "new-dashboard", default = true)]
NewDashboard,
#[feature(key = "beta-features")]
BetaFeatures,
}
async fn example(client: &TogglyClient) {
let enabled = Features::DarkMode.is_enabled(client, Default::default()).await.unwrap();
}
Configuration Options
use std::time::Duration;
use toggly::TogglyConfig;
let config = TogglyConfig::builder()
.app_key("your-app-key")
.environment("production")
.base_url("https://app.toggly.io/")
.definitions_url("https://definitions.toggly.io/")
.refresh_interval(Duration::from_secs(300))
.http_timeout(Duration::from_secs(10))
.cache_ttl(Duration::from_secs(60))
.cache_max_entries(10_000)
.enable_undefined_in_dev(true)
.disable_background_refresh(false)
.build();
Custom Filter Evaluators
Register custom filter evaluators for advanced targeting:
use toggly::eval::{Evaluator, Registry};
use toggly::{EvalContext, definitions::FeatureFilter};
use std::sync::Arc;
struct MyCustomEvaluator;
impl Evaluator for MyCustomEvaluator {
fn evaluate(
&self,
feature_key: &str,
filter: &FeatureFilter,
context: &EvalContext,
) -> toggly::Result<bool> {
Ok(true)
}
}
let registry = Registry::with_defaults();
registry.register("MyCustomFilter", Arc::new(MyCustomEvaluator));
Error Handling
use toggly::{TogglyClient, EvalContext, Error};
async fn safe_feature_check(client: &TogglyClient) -> bool {
match client.is_enabled("my-feature", EvalContext::default()).await {
Ok(enabled) => enabled,
Err(Error::FeatureNotFound(_)) => {
tracing::warn!("Feature not found, using default");
false
}
Err(e) => {
tracing::error!("Feature check failed: {}", e);
false
}
}
}
Requirements
- Rust 1.70+ (MSRV)
- Tokio runtime
Documentation
License
MIT License - see LICENSE for details.
Support