| Crates.io | abundantis |
| lib.rs | abundantis |
| version | 0.1.9 |
| created_at | 2026-01-13 12:28:12.948246+00 |
| updated_at | 2026-01-23 11:24:06.389002+00 |
| description | High-performance unified environment variable management from multiple sources |
| homepage | |
| repository | https://github.com/ph1losof/abundantis |
| max_upload_size | |
| id | 2040028 |
| size | 309,645 |
Abundantis is a Rust crate for unified environment variable management across multiple sources. It serves as the foundational layer for the Ecolog ecosystem while being independently usable for any project.
| Feature | Traditional .env libs | Abundantis |
|---|---|---|
| Source Aggregation | Single source | Multiple sources with precedence |
| Interpolation | Simple ${VAR} |
Full shell syntax ${VAR:-default}, ${VAR:+alt} |
| Workspace Support | â | â Monorepo-aware context resolution |
| Async Support | â | â Tokio-based async API |
| Event System | â | â Reactive change notifications |
| Extensibility | â | â Plugin architecture for custom sources |
| Remote Sources | â | ð Architecture prepared (Vault, AWS, GCP, Azure) |
âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
â Abundantis â
â âââââââââââââââ âââââââââââââââ âââââââââââââââ â
â â Source â â Resolution â â Workspace â â
â â Registry ââââ Engine ââââ Manager â â
â âââââââââââââââ âââââââââââââââ âââââââââââââââ â
â â â â â
â âž âž âž â
â âââââââââââââââ âââââââââââââââ âââââââââââââââ â
â â Event â â Cache â â Config â â
â â Bus â â System â â Loader â â
â âââââââââââââââ âââââââââââââââ âââââââââââââââ â
âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
korni crate for .env file parsinggermi crate for variable resolutiondashmap for shared statehashbrown for optimized hashingcompact_str to reduce allocationsEnvSource and AsyncEnvSource traitsSourceRegistry for extensibilitysource/)Purpose: Provides extensible system for environment variable sources
Components:
traits.rs: Core source abstractions
EnvSource: Synchronous source traitAsyncEnvSource: Asynchronous source trait (future-proofing)SourceFactory: Factory pattern for dynamic source creationSourceId, SourceType, Priority, SourceCapabilities: Source metadataregistry.rs: Centralized source management
memory.rs: In-memory source for programmatic usage
parking_lot::Mutexindexmap::IndexMapfile.rs: File-based .env source
lru cratekornishell.rs: Shell environment source
std::env accessArchitectural Choice:
config/)Purpose: Hierarchical configuration system
Components:
AbundantisConfig: Root configuration with Serde supportWorkspaceConfig: Monorepo detection and settingsResolutionConfig: Variable resolution behaviorInterpolationConfig: Interpolation rules and limitsFileResolutionConfig: .env file merging strategyCacheConfig: Cache tuning parametersArchitectural Choices:
workspace/)Purpose: Monorepo-aware context resolution
Components:
context.rs: Workspace and package context definitions
WorkspaceContext: Root, package, and env file mappingPackageInfo: Package metadata (root, name, relative path)manager.rs: Workspace state and discovery
hashbrown::HashMapprovider/: Monorepo tool integrations
Architectural Choices:
DashMap for concurrent accessglobset for flexibilityresolution/)Purpose: Intelligent variable resolution with interpolation
Components:
ResolvedVariable: Fully resolved variable with metadata
DependencyGraph: Placeholder for future interpolation graph
ResolutionEngine: Core resolution logic
ResolutionCache: Multi-level caching system
Architectural Choices:
germi for performanceerror.rs)Purpose: Comprehensive error reporting with LSP integration
Components:
AbundantisError: Main error type with variants
SourceError: Source-specific errors
Diagnostic: LSP-compatible diagnostic messages
Architectural Choices:
events/)Purpose: Reactive updates and notifications
Components:
AbundantisEvent: Event types
EventSubscriber: Trait for event handling
EventBus: Event publishing (stubbed)
Architectural Choices:
core/)Purpose: Fluent API for Abundantis construction
Components:
Architectural Choices:
1. Load Configuration (AbundantisConfig)
â
2. Initialize WorkspaceManager
- Detect monorepo type
- Discover packages
- Build context cache
â
3. Initialize SourceRegistry
- Register default sources (file, shell, memory)
- Register custom sources if configured
â
4. Initialize ResolutionEngine
- Setup dependency graph
- Initialize cache
â
5. Initialize EventBus
- Setup subscribers
â
6. Create Abundantis instance
â
7. Load all sources
- Each source produces a Snapshot
- Store in SourceRegistry
Request: get("DATABASE_URL", path)
â
1. WorkspaceManager.context_for_file(path)
- Lookup in context cache
- Return WorkspaceContext
â
2. ResolutionEngine.resolve(key, context, registry)
- Load all source snapshots
- Aggregate variables by priority
â
3. For each source (highest to lowest priority):
- Find variable in source
- If found, apply interpolation
- Detect circular dependencies
- Resolve references recursively
- Apply depth limit (default: 64)
- Return resolved value
â
4. Return ResolvedVariable with metadata
Level 1: Memory Source Cache
- Direct variable access in memory
- No locking needed for reads
Level 2: Source Snapshot Cache
- Cached parsed variables per source
- LRU eviction (default: 1000 entries)
- Invalidated on source changes
Level 3: Resolution Cache
- Cached resolved variables
- Hot cache for frequently accessed keys
- TTL-based invalidation (default: 5m)
Abundantis is optimized for speed:
| Operation | Performance | Notes |
|---|---|---|
| Cached variable lookup | < 100ns |
Hot cache access |
| File source load | < 1ms |
Zero-copy parsing via korni |
| Variable interpolation | < 500Ξs |
SIMD via germi |
| All variables enumeration | < 5ms |
For 1000 variables |
| Memory overhead | ~1MB |
For 10,000 variables |
Cow<'a, str> from kornimemchr and optimized algorithms in germiDashMap for concurrent cache accessCompactString optimization for keys/valueshashbrown with inline arrays for small mapsAdd to your Cargo.toml:
[dependencies]
abundantis = "0.1"
With specific features:
[dependencies]
abundantis = { version = "0.1", features = ["full"] }
file (default) - FileSource for .env filesshell (default) - ShellSource for process environmentasync - Async runtime support (tokio) for async sources and APIswatch - File watching via notify with debouncingfull - Enables all featuresuse abundantis::{Abundantis, config::MonorepoProviderType};
#[tokio::main]
async fn main() -> abundantis::Result<()> {
let abundantis = Abundantis::builder()
.root(".")
.provider(MonorepoProviderType::Custom)
.with_shell()
.env_files(vec![".env", ".env.local"])
.build()
.await?;
// Get a variable
if let Some(var) = abundantis.get("DATABASE_URL").await {
println!("Database: {}", var.resolved_value);
println!("Source: {:?}", var.source);
}
// Get all variables for a file
let vars = abundantis.all_for_file(Path::new("src/main.rs")).await;
for var in vars {
println!("{} = {}", var.key, var.resolved_value);
}
Ok(())
}
use abundantis::{MemorySource, Abundantis};
#[tokio::main]
async fn main() -> abundantis::Result<()> {
let abundantis = Abundantis::builder()
.with_source(MemorySource::new())
.build()
.await?;
// Set variables programmatically
// (for testing or dynamic config)
let vars = abundantis.all().await;
Ok(())
}
use abundantis::{Abundantis, events::{AbundantisEvent, EventSubscriber}};
struct MySubscriber;
impl EventSubscriber for MySubscriber {
fn on_event(&self, event: &AbundantisEvent) {
match event {
AbundantisEvent::VariablesChanged { added, removed, .. } => {
println!("Added: {:?}, Removed: {:?}", added, removed);
}
_ => {}
}
}
}
#[tokio::main]
async fn main() -> abundantis::Result<()> {
let subscriber = std::sync::Arc::new(MySubscriber);
let abundantis = Abundantis::builder()
.subscribe(subscriber)
.build()
.await?;
// Subscribe to channel for async handling
let mut rx = abundantis.event_bus().subscribe_channel();
while let Ok(event) = rx.recv().await {
println!("Event: {:?}", event);
}
Ok(())
}
| Method | Description | Default |
|---|---|---|
root(path) |
Workspace root directory | current_dir() |
provider(type) |
Monorepo provider type | Required |
with_shell() |
Include shell environment source | false |
env_files(patterns) |
Env file patterns to scan | .env, .env.local, .env.development, .env.production |
cascading(enabled) |
Enable cascading env inheritance | false |
interpolation(enabled) |
Enable variable interpolation | true |
max_interpolation_depth(n) |
Max recursion depth for interpolation | 64 |
precedence(order) |
Source priority order | [Shell, File] |
watch(enabled) |
Enable file watching | false |
event_buffer_size(n) |
Event channel buffer size | 256 |
subscribe(subscriber) |
Add event subscriber | None |
Sources are checked in the order specified. Higher priority wins conflicts:
use abundantis::{config::SourcePrecedence, Abundantis};
let abundantis = Abundantis::builder()
.precedence(vec![
SourcePrecedence::Shell, // Highest priority (100)
SourcePrecedence::File, // Medium priority (50)
// SourcePrecedence::Remote, // Prepared for future (75)
])
.build()
.await?;
Abundantis includes built-in support for popular monorepo tools:
| Provider | Config File | Detection |
|---|---|---|
| Turbo | turbo.json |
Delegates to pnpm/npm/yarn |
| Nx | nx.json |
â |
| Lerna | lerna.json |
â |
| pnpm | pnpm-workspace.yaml |
â |
| npm/yarn | package.json workspaces |
â |
| Cargo | Cargo.toml |
â |
| Custom | Configured via API | â |
use abundantis::{config::MonorepoProviderType, Abundantis};
// Auto-detect provider
let abundantis = Abundantis::builder()
.provider(MonorepoProviderType::Turbo)
.build()
.await?;
EnvSource (synchronous)
âââ MemorySource
âââ FileSource
âââ ShellSource
AsyncEnvSource (asynchronous, future-proofing)
âââ (future remote sources)
SourceFactory
âââ FileSourceFactory
âââ ShellSourceFactory
âââ MemorySourceFactory
MonorepoProvider
âââ CargoProvider
âââ TurboProvider
âââ NxProvider
âââ LernaProvider
âââ PnpmProvider
âââ NpmProvider
âââ CustomProvider
SourceError â AbundantisError::Source â Result<T>
Severity Levels: Error, Warning, Info, Hint Diagnostic Codes: EDFxxx (env file), RESxxx (resolution), WSxxx (workspace)
You can extend Abundantis with custom environment variable sources:
use abundantis::{
source::{EnvSource, SourceId, SourceType, Priority, SourceCapabilities, SourceSnapshot, ParsedVariable, VariableSource},
error::SourceError,
};
struct MyCustomSource {
id: SourceId,
}
impl MyCustomSource {
fn new() -> Self {
Self {
id: SourceId::new("my-custom"),
}
}
}
impl EnvSource for MyCustomSource {
fn id(&self) -> &SourceId {
&self.id
}
fn source_type(&self) -> SourceType {
SourceType::File // Or Memory, Remote
}
fn priority(&self) -> Priority {
Priority::FILE // Or custom value
}
fn capabilities(&self) -> SourceCapabilities {
SourceCapabilities::READ | SourceCapabilities::CACHEABLE
}
fn load(&self) -> Result<SourceSnapshot, SourceError> {
// Load your variables here
let vars = vec![
ParsedVariable::simple(
"CUSTOM_VAR",
"custom_value",
VariableSource::Memory,
),
];
Ok(SourceSnapshot {
source_id: self.id.clone(),
variables: vars.into(),
timestamp: std::time::Instant::now(),
version: None,
})
}
fn has_changed(&self) -> bool {
// Return true if source needs reload
true
}
fn invalidate(&self) {
// Clear any internal cache
}
}
Run tests:
cargo test --all-features
Run benchmarks:
cargo bench --all-features
tests/
âââ config_tests.rs (42 tests)
âââ error_tests.rs (38 tests)
âââ integration_tests.rs (35 tests)
âââ memory_source_tests.rs (27 tests)
âââ source_traits_tests.rs (32 tests)
âââ workspace_tests.rs (26 tests)
Total: 212 tests
default: Enables file and shell sourcesfile: File source with korni parsingshell: Shell environment sourceasync: Async runtime with tokiowatch: File system watching with notifyfull: All features enabled#[cfg(feature = "async")]
#[cfg(feature = "file")]
#[cfg(feature = "shell")]
#[cfg(feature = "watch")]
We welcome contributions! Please see CONTRIBUTING.md for guidelines.
Licensed under either of:
at your option.