Spring Boot-style configuration for Python applications
Spring Boot-style configuration management for Python.
SprigConfig is a production-ready, lightweight configuration system that brings layered YAML configuration, runtime-driven profile selection, deep merge semantics, secure secrets handling, and complete provenance tracking to Python applications.
Think of it as Spring Boot’s configuration philosophy for Python—but designed from the ground up for Python’s simplicity and flexibility.
SprigConfig solves a real problem: configuration management should be predictable, debuggable, and secure—especially at 3am during an outage.
✅ Layered configuration with deterministic deep merge semantics ✅ Runtime-driven profiles (dev, test, prod) that never come from files ✅ Recursive imports with cycle detection and provenance tracking ✅ Encrypted secrets that stay encrypted until you need them ✅ Deterministic, debuggable behavior you can reason about ✅ Backward compatibility is critical ✅ Secure by default for sensitive values
pip install sprig-config
Or with Poetry:
poetry add sprig-config
Requirements: Python 3.13+
Configuration files (config/ directory):
# config/application.yml (base config)
server:
port: 8080
host: localhost
debug: false
database:
host: localhost
port: 5432
logging:
level: INFO
# config/application-dev.yml (development overlay)
server:
port: 9090 # Override base
debug: true
logging:
level: DEBUG # Override base
Python code:
from sprigconfig import load_config
# Load dev configuration (profile is runtime-driven)
cfg = load_config(profile="dev")
print(cfg["server.port"]) # → 9090 (from dev overlay)
print(cfg["server.host"]) # → localhost (from base)
print(cfg["server.debug"]) # → true (from dev overlay)
print(cfg["database.host"]) # → localhost (from base, not overridden)
print(cfg["app.profile"]) # → dev (injected at runtime)
That’s it! Configuration is loaded, merged, and available via simple dotted-key access.
| Feature | What It Does |
|---|---|
| Profile Overlays | Environment-specific config (dev, test, prod) selected at runtime |
| Deep Merge | Predictable layering with collision warnings and full provenance |
| Recursive Imports | Modular configuration with imports: directive and cycle detection |
| Secure Secrets | Fernet-encrypted ENC(...) values, decrypted on-demand with lazy evaluation |
| Format Support | YAML (recommended), JSON, and TOML |
| CLI Tools | Inspect, debug, and validate merged configuration from command line |
| Dependency Injection | ConfigValue descriptors, @ConfigurationProperties, and @config_inject decorators |
| Dynamic Instantiation | Hydra-style _target_ support for instantiating classes from config |
| Provenance Tracking | Know exactly where every value came from |
# YAML (default, recommended)
server:
port: 8080
{
"server": {
"port": 8080
}
}
[server]
port = 8080
All files in a single load must use the same format.
Start here:
Dive deeper into SprigConfig’s behavior:
imports:For power users and framework integration:
For developers working on SprigConfig itself:
Guides for running SprigConfig in production:
SprigConfig follows a predictable, debuggable flow:
1. Profile Resolution (runtime-driven)
↓
Explicit: load_config(profile="prod")
Or: APP_PROFILE=prod environment variable
Or: pytest context → "test"
Or: default → "dev"
2. File Loading & Merging
↓
Load application.yml (base)
+ Overlay application-<profile>.yml
+ Process recursive imports: [...]
= Deep merge with collision warnings
3. Value Processing
↓
Expand ${VAR} environment variables
Convert ENC(...) → LazySecret objects
Inject app.profile (runtime value)
Inject sprigconfig._meta (provenance)
4. Return Config Object
↓
Dict-like interface with dotted-key access
Located in the SprigConfig source (src/sprigconfig/):
| Module | Purpose |
|---|---|
config_loader.py |
Main loading logic, merging, profile selection |
config.py |
Config class (dict-like interface, dotted-key access) |
lazy_secret.py |
LazySecret class for deferred, secure decryption |
deepmerge.py |
Deep merge algorithm with collision warnings |
injection.py |
Dependency injection (ConfigValue, @ConfigurationProperties, @config_inject) |
instantiate.py |
Dynamic class instantiation via _target_ patterns |
exceptions.py |
Custom exceptions (ConfigLoadError, etc.) |
config_singleton.py |
Thread-safe cached loader |
cli.py |
Command-line interface for inspection/debugging |
SprigConfig is built on these core principles (non-negotiable):
SprigConfig is ideal for:
How does SprigConfig compare?
| Feature | SprigConfig | Spring Python | python-dotenv | Pydantic | hydra | pyyaml |
|---|---|---|---|---|---|---|
| Layered config | ✅ | ❌ | ❌ | ✅ | ✅ | ❌ |
| Profile overlays | ✅ | ❌ | ❌ | ❌ | ✅ | ❌ |
| Recursive imports | ✅ | ❌ | ❌ | ❌ | ✅ | ❌ |
| Encrypted secrets | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ |
| Provenance tracking | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ |
| Multiple formats | ✅ | ✅ | ❌ | ✅ | ✅ | YAML only |
| CLI debugging | ✅ | ❌ | ❌ | ❌ | ✅ | ❌ |
| Spring Boot style | ✅ | ⚠️ | ❌ | ❌ | ❌ | ❌ |
| Dependency injection | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ |
| Dynamic instantiation | ✅ | ❌ | ❌ | ❌ | ✅ | ❌ |
| Validation | ⚠️ (manual) | ❌ | ❌ | ✅ | ✅ | ❌ |
| Python 3.13+ | ✅ | ❌ | ✅ | ✅ | ✅ | ✅ |
Notes on Spring Python: Spring Python (v1.2.1) is an older project that provides IoC container and YAML/XML configuration, inspired by Spring Framework. However, it only supports Python 2.6+ (not Python 3) and lacks modern features like profile overlays, encrypted secrets, and provenance tracking. For Python developers seeking Spring-style patterns, SprigConfig offers a modern, actively-maintained alternative.
MIT License. See LICENSE for details.
SprigConfig — Stable. Secure. Predictable.