FluxDI - Semi-automatic Dependency Injector
A lightweight, type-safe dependency injection container for Rust applications. FluxDI provides ergonomic service registration (including trait-object bindings), transient/root/module/scoped lifetimes, semi-automatic dependency resolution, and circular dependency detection.
โจ Features
- ๐ Type-Safe: Leverages Rust's type system for compile-time safety
- ๐ Transient Services: Create new instances on each request
- ๐ Singleton Services: Shared instances with reference counting via
Arc/Rc - ๐งญ Scoped Context: Per-request/task instances via
create_scope()+Provider::scoped(...) - ๐ Circular Detection: Prevents infinite loops in dependency graphs
- โ Error Handling: Comprehensive error types with detailed messages
- ๐ Optional Logging: Built-in logging initialization and tracing integration
- ๐ Zero-Cost Abstractions: Feature gates enable compile-time optimization
- ๐งต Thread-Safe by Default: Uses
Arc+RwLockfor concurrent access - ๐ฆ Module System: Organize services into reusable modules
- ๐๏ธ Enterprise Ready: Supports layered architecture, repository pattern, and use cases
๐ฆ Installation
Add this to your Cargo.toml:
[]
= { = "../fluxdi" } # For local development
Or from crates.io (when published):
[]
= "1.2.1"
๐ Quick Start
use ;
// Define your services
;
๐ Documentation (mdBook)
FluxDI now includes an mdBook under docs/.
Build docs:
Serve locally:
Examples
FluxDI includes sixteen comprehensive examples showcasing different use cases and patterns:
1. Basic Example
Location: examples/basic/
A simple introduction to FluxDI fundamentals:
- Service registration with
InjectorandProvider - Transient and singleton lifetimes
- Basic dependency resolution with
try_resolve() - Error handling with
Resulttypes
Run:
2. Injectable Macro Example
Location: examples/injectable-macro/
Demonstrates #[derive(Injectable)] as an alternative to manual provider closures:
- Same behavior as manual
Provider::root(|inj| { ... }) - Reduces boilerplate when all dependencies are
Shared<T> - Side-by-side parity with
examples/basic
Run:
3. Complex Example
Location: examples/complex/
Demonstrates enterprise-grade architecture with:
- Domain Layer: Clear entity definitions and repository interfaces
- Application Layer: Use case pattern for business logic
- Infrastructure Layer: SQLite persistence with concrete implementations
- Dependency Injection: Multi-level service composition
- Module System: Modular DI configuration with imported modules
Architecture:
core/
โโโ domain/ (User, Todo entities & repository traits)
โโโ application/ (CreateUserUseCase, GetAllTodoUseCase, etc.)
infra/
โโโ di/ (Modules & dependency registration)
โโโ persistence/ (SQLite repositories)
Run:
Run Tests:
4. Actix-web Example
Location: examples/actix/
Minimal Actix-web integration with FluxDI extractors:
- App-level injector state via
injector_data(...) - Per-handler dependency resolution via
fluxdi::actix::Resolved<T> - Zero-boilerplate extraction for services from the container
Run:
Then request:
5. Axum REST API Example
Location: examples/axum/
Real-world REST API integration with Axum web framework:
- HTTP handler functions with DI-resolved dependencies
- Structured JSON responses with error handling
- CRUD endpoints for Users and Todos
- Service state management via
InjectorState - Automatic per-handler DI resolution via
Resolved<T>extractor - Dependency resolution per-request
- Lifecycle-driven startup via
Module::on_start+Application::bootstrap().await
Features:
POST /users- Create userGET /users- List all usersGET /users/{id}- Get user by IDDELETE /users/{id}- Delete userPOST /todos- Create todoGET /todos- List all todosPUT /todos/{id}/status- Update todo statusDELETE /todos/{id}- Delete todo
Run:
# Terminal 1: Start server
# Terminal 2: Run comprehensive test suite
The test suite includes:
- Server health checks
- Sequential dependency extraction between requests
- HTTP status code validation
- JSON response parsing and assertion
6. Axum Lifecycle Example
Location: examples/axum-lifecycle/
Demonstrates module lifecycle startup with async hooks:
- Register
Routeras DI service - Start
axum::servefromModule::on_start(...) - Bootstrap with
Application::bootstrap().await
Run:
7. Module Sync Bootstrap Example
Location: examples/module-sync/
Minimal module-centric synchronous startup:
- Uses
Module::configure(...)as the single registration hook - Starts with
Application::bootstrap_sync()
Run:
8. Module Async Bootstrap Example
Location: examples/module-async/
Async instance registration and lifecycle orchestration:
- Registers async instance via
Provider::root_async(...) - Uses
Application::bootstrap().await - Demonstrates lifecycle prewarm in
on_start(...)
Run:
9. SeaORM SQLite Module Example
Location: examples/seaorm-sqlite/
SeaORM + SQLite integration through FluxDI module lifecycle:
- Registers
DatabaseConnectionviaProvider::root_async(...) - Uses
Module::on_start(...)to run a startup connectivity check (SELECT 1) - Boots with
Application::bootstrap().await
Run:
10. Dual HTTP Random-Port Example
Location: examples/dual-http-random-port/
Runs two HTTP services in one module lifecycle:
- Randomly binds both services in
30000-65535 - Starts both servers concurrently in
on_start(...) - Gracefully aborts both tasks in
on_stop(...)
Run:
11. Mixed Sync + Async Module Example
Location: examples/module-mixed-sync-async/
Demonstrates sync and async providers in the same module:
- Registers sync providers with
Provider::root(...)andProvider::transient(...) - Registers async providers with
Provider::root_async(...) - Uses sync
resolve(...)and asynctry_resolve_async(...).awaitin the same startup flow
Run:
12. Named Bindings Example
Location: examples/named-bindings/
Demonstrates multiple implementations for one trait via names:
- Registers two
dyn CacheBackendproviders (primary,fallback) - Resolves each implementation with
resolve_named::<T>(name) - Shows strategy/backends selection without changing consumer code
Run:
13. Multi-binding Pipeline Example
Location: examples/multi-binding-pipeline/
Demonstrates plugin/middleware pipeline composition:
- Registers multiple
dyn Middlewareproviders into one set - Resolves all with
resolve_all::<T>() - Executes in deterministic registration order
Run:
14. Graph Tooling Example
Location: examples/graph-tooling/
Demonstrates graph export and validation:
- Declares dependencies with
with_dependency/with_set_dependency - Runs
validate_graphand prints issues (if any) - Exports DOT and Mermaid via
dependency_graph
Run:
15. Decorator Example
Location: examples/decorator/
Demonstrates Provider::with_decorator() for cross-cutting composition:
- Wraps services with logging, caching, or retry without modifying business logic
- Multiple decorators chain with deterministic order
- Works with trait objects
Run:
16. Scoped Context Example
Location: examples/scoped-context/
Demonstrates request/task level scope isolation:
- Registers scoped services with
Provider::scoped(...) - Creates runtime scopes with
Injector::create_scope() - Shows per-scope cache isolation and root cache sharing
Run:
Usage Guide
Service Registration
Transient Services
Create new instances on each request:
use ;
use Uuid;
let injector = root;
// Transient: new instance each time (default behavior)
injector.;
let logger1 = injector.;
let logger2 = injector.;
// logger1 and logger2 are different instances
Singleton Services
Create once and share across all dependents:
use ;
let injector = root;
// Singleton: same instance every time
injector.;
let config1 = injector.;
let config2 = injector.;
// config1 and config2 point to the same instance
Scoped Services
Create one instance per runtime scope:
use ;
let injector = root;
injector.;
let scope = injector.create_scope;
let ctx1 = scope.;
let ctx2 = scope.;
assert!;
Error Handling
FluxDI provides both panicking and non-panicking variants:
use ;
let injector = root;
injector.;
// Non-panicking (try_resolve returns Result)
match injector.
// Trying to resolve an unregistered type
match injector.
Provider Override (Testing)
You can replace existing providers for test and integration scenarios:
use ;
let injector = root;
injector.;
injector
.
.expect;
assert_eq!;
Named Bindings
Register and resolve multiple implementations for the same type/trait:
use ;
;
;
let injector = root;
injector.;
injector.;
let primary = injector.;
let fallback = injector.;
assert_eq!;
assert_eq!;
Multi-binding
Register multiple implementations in one set and resolve them together:
use ;
;
;
let injector = root;
injector.;
injector.;
let middlewares = injector.;
let order: = middlewares.iter.map.collect;
assert_eq!;
Ordering strategy:
- Parent injector bindings come first.
- Child injector bindings come after parent bindings.
- Within each injector, registration order is preserved.
Graph Tooling
You can export dependency graphs and validate missing dependencies/cycles:
use ;
;
;
let injector = root;
injector.;
injector.;
let report = injector.validate_graph;
assert!;
let graph = injector.dependency_graph;
let dot = graph.to_dot;
let mermaid = graph.to_mermaid;
assert!;
assert!;
CI-friendly guard:
injector.try_validate_graph?;
Derive Macro (Injectable)
Enable derive support:
[]
= { = "../fluxdi", = ["macros"] }
use ;
Dependency Injection
Services can depend on other services. Use module-based registration for clean organization:
use ;
// Define a module for persistence services
;
let injector = root;
let module = PersistenceModule;
module.providers;
let repo = injector.;
๐ Advanced Features
Circular Dependency Detection
FluxDI automatically detects and prevents circular dependencies by tracking resolution paths:
use ;
// Example: attempting to create circular dependencies will fail
let injector = root;
// These registrations will create a circular dependency
// Attempting to resolve either service will result in an error
// Error: "Circular dependency detected in resolution path"
Resource Limits
You can constrain concurrent factory execution per provider:
use ;
let injector = root;
injector.;
Available policies:
Policy::Deny: fail immediately withResourceLimitExceeded.Policy::Block: wait for a free slot (supported whenthread-safeis enabled).
Timeout support:
use Duration;
use ;
injector.;
Async non-blocking wait (optional):
[]
= { = "../fluxdi", = ["thread-safe", "async-factory", "resource-limit-async"] }
Logging
Enable the logging feature for a default text logger:
[]
= { = "../fluxdi", = ["logging"] }
logging reads RUST_LOG and falls back to info when unset.
For rich node-level diagnostics across registration, provider lookup, cache hit/miss, and factory execution:
RUST_LOG=fluxdi=trace
Tracing Integration
Enable the tracing feature for automatic logging:
[]
= { = "../fluxdi", = ["tracing"] }
use ;
use info;
;
async
OpenTelemetry Bridge
Enable OpenTelemetry bridge support with the opentelemetry feature:
[]
= { = "../fluxdi", = ["opentelemetry"] }
= { = "0.29", = ["trace"] }
use TracerProvider as _;
use SdkTracerProvider;
use opentelemetry_layer;
use ;
fluxdi only provides tracing-to-OTel wiring helpers (opentelemetry_layer and
try_init_opentelemetry) and does not auto-install exporters.
Service Metrics and Prometheus Export
Enable metrics collection:
[]
= { = "../fluxdi", = ["metrics"] }
Enable Prometheus text export (prometheus implies metrics):
[]
= { = "../fluxdi", = ["prometheus"] }
use ;
Async Factory Support
Enable async factories with the async-factory feature:
[]
= { = "../fluxdi", = ["async-factory"] }
use ;
async
Resolution strategy:
- If a type is registered with
Provider::*_async, resolve it withtry_resolve_async/resolve_async. - Sync providers (
Provider::root/singleton/transient) work with both sync and async resolve APIs. - Sync resolve against an async provider returns
AsyncFactoryRequiresAsyncResolve.
Runnable example:
Module Async Lifecycle Hooks
Module now supports async hooks for startup/shutdown orchestration:
configure(injector)as the primary, unified provider registration hookproviders_async(injector)as a legacy-compatible alias (new code should useconfigure)on_start(injector)to start runtime resources (for example, an Axum listener)on_stop(injector)to release resources in reverse module order
Use Application::bootstrap().await and Application::shutdown().await as the unified lifecycle APIs.
For production patterns (graceful shutdown, timeouts, background tasks), see the Production Patterns section in the docs (mdbook serve docs).
use ;
;
async
๐งช Testing
Unit Tests
Run the crate test suite:
# Run all tests for the workspace
# Run tests for the fluxdi crate only
# Run with tracing feature
# Run with async factory feature
# Run documentation tests
๐ Project Structure
fluxdi/
โโโ fluxdi/ # FluxDI library crate
โ โโโ src/ # core implementation (injector, provider, runtime)
โ โโโ README.md # This file
โโโ examples/
โ โโโ basic/ # Basic usage example with simple DI
โ โโโ complex/ # Advanced DI patterns with SQLite, repositories, use cases
โ โ โโโ src/
โ โ โ โโโ core/ # Domain (entities, use cases)
โ โ โ โโโ infra/ # Infrastructure (persistence, DI configuration)
โ โ โโโ test.sh # Test script for complex example
โ โโโ actix/ # Actix-web integration example
โ โ โโโ src/
โ โ โโโ main.rs # Minimal Actix extractor usage
โ โโโ axum-lifecycle/ # Axum startup in Module::on_start lifecycle hook
โ โ โโโ src/
โ โ โโโ main.rs # Lifecycle-driven server bootstrap
โ โโโ module-sync/ # Sync module bootstrap with configure()
โ โ โโโ src/
โ โ โโโ main.rs # bootstrap_sync usage
โ โโโ module-async/ # Async module bootstrap with async providers
โ โ โโโ src/
โ โ โโโ main.rs # bootstrap().await + root_async provider
โ โโโ module-mixed-sync-async/ # Sync and async providers in one module
โ โ โโโ src/
โ โ โโโ main.rs # mixed resolve + try_resolve_async usage
โ โโโ multi-binding-pipeline/ # Ordered plugin/middleware pipeline with resolve_all
โ โ โโโ src/
โ โ โโโ main.rs # provide_into_set + resolve_all usage
โ โโโ graph-tooling/ # Dependency graph export + validation example
โ โ โโโ src/
โ โ โโโ main.rs # dependency_graph + validate_graph
โ โโโ named-bindings/ # Named/strategy bindings for one trait
โ โ โโโ src/
โ โ โโโ main.rs # provide_named + resolve_named example
โ โโโ seaorm-sqlite/ # SeaORM + SQLite module lifecycle example
โ โ โโโ src/
โ โ โโโ main.rs # on_start connectivity check (SELECT 1)
โ โโโ dual-http-random-port/ # Two HTTP servers with random 30000-65535 ports
โ โ โโโ src/
โ โ โโโ main.rs # concurrent startup in on_start + abort in on_stop
โ โโโ scoped-context/ # Runtime scoped injector example
โ โ โโโ src/
โ โ โโโ main.rs # create_scope + Provider::scoped usage
โ โโโ axum/ # REST API with Axum web framework
โ โโโ src/
โ โ โโโ main.rs # HTTP handlers with DI integration
โ โโโ test.sh # Comprehensive API test suite
โโโ README.md
๐ง Configuration
Feature Flags
FluxDI exposes a small set of feature flags. See fluxdi/Cargo.toml for the authoritative list:
debug(enabled by default) โ enables extra debug formatting in selected types and errors.thread-safe(optional) โ switches internal shared pointer and synchronization primitives toArc+RwLockfor concurrent access.lock-free(optional) โ usesDashMapfor provider/instance stores inthread-safemode.logging(optional) โ enablestry_init_logging()/init_logging()helpers andRUST_LOGfilter support.tracing(optional) โ enables tracing logs and spans during registration and resolution.opentelemetry(optional) โ adds OpenTelemetry bridge helpers influxdi::observability.metrics(optional) โ enables internal injector counters andInjector::metrics_snapshot().prometheus(optional) โ enablesInjector::prometheus_metrics()text export (includesmetrics).actix(optional) โ enables Actix-web integration helpers and extractors (and enablesthread-safe).axum(optional) โ enables Axum integration helpers and extractors (and enablesthread-safe).async-factory(optional) โ enablesProvider::*_asyncandInjector::*_resolve_asyncAPIs.resource-limit-async(optional) โ uses Tokio semaphore for non-blocking async waits in resource limits.macros(optional) โ enables#[derive(Injectable)]viafluxdi-macros.lifecycle(optional) โ enablesBootstrapOptions/ShutdownOptionstimeout support for production environments.
Decorators (Provider::with_decorator()) work with any feature set; no extra flag required.
The crate default is currently default = ["debug"]. If you need multithreaded use, enable thread-safe.
Environment Variables
When using the logging (or tracing) feature, you can control log levels:
# Set log level
RUST_LOG=debug
# Enable only FluxDI logs
RUST_LOG=fluxdi=info
๐ค Contributing
Contributions are welcome! Please feel free to submit a Pull Request. For major changes, please open an issue first to discuss what you would like to change.
Development Setup
- Clone the repository:
- Run tests:
- Check formatting:
- Run clippy:
๐ Roadmap & TODO
๐งต Thread Safety
- Arc-based Runtime: Thread-safe version of FluxDI using
Arcinstead ofRc(implemented behind thethread-safefeature) - Send + Sync Services: Support for
Send + Syncservices in thread-safe mode (enforced by API bounds) - Concurrent Access: Concurrent reads/writes supported via
RwLockin thread-safe mode - Lock-free Operations: Optional
lock-freefeature (DashMap) for high-concurrency resolve paths
๐ง Advanced Features
- Lazy Initialization: Singleton instances are created on first
resolve - Service Metrics: Internal counters + timing totals via
metrics_snapshot - Resource Limits: Per-provider concurrent creation limits with
Limits+Policy - Named Bindings: Resolve multiple implementations by key with
provide_named/resolve_named - Multi-binding: Resolve ordered plugin sets with
provide_into_set/resolve_all - Graph Tooling: Export dependency graph and validate missing/cyclic dependencies
- Scoped Context:
create_scope+Provider::scopedruntime scope isolation
๐ฆ Ecosystem Integration
- Async Factory Support: Async/await provider factories via
Provider::*_async+Injector::*_resolve_async - Actix-web Integration:
fluxdi::actix::{Resolved<T>, ServiceConfigExt, injector_data} - Axum Integration: Demonstrated with REST API example and state management
- Axum Auto-Resolve Plugin:
fluxdi::axum::Resolved<T>extractor for per-handler resolution - Rocket Integration: Layer and extractor support for Rocket web framework
Architectural Patterns
- Repository Pattern: Demonstrated in complex example with SQLite repositories
- Layered Architecture: Clean separation of domain, application, and infrastructure layers
- Use Case Pattern: Business logic encapsulated in use cases with DI
- Web Framework Integration: Explored with Axum + Actix-web
Developer Experience
- Derive Macros: Auto-generate factory functions from service structs (
#[derive(Injectable)]) - Error Suggestions: Better error messages with fix suggestions
๐ Observability
- OpenTelemetry: Optional tracing bridge helpers via
opentelemetry_layer/try_init_opentelemetry - Prometheus Metrics:
prometheus_metrics()text export for scraping
๐ฏ Performance
- Memory Optimization: Reduced memory footprint for large containers
๐ License
This project is licensed under the MIT License - see the LICENSE file for details.
๐ Acknowledgments
- Inspired by dependency injection patterns from other languages and frameworks
- Built with โค๏ธ using Rust's powerful type system
- Thanks to the Rust community for excellent crates and documentation
FluxDI - A semi-automatic dependency injection container for Rust
Repository: DaiYuANg/fluxdi
Made with โค๏ธ by the Binary Sea Team