Configuration Providers
The configuration system uses property sources to supply configuration values. Multiple sources can be active simultaneously, with values resolved by priority order. The IDK ships with local sources; the EDK adds cloud and secret vault providers, and the VDX platform adds database persistence.
Available Providers
IDK (Always Available)
| Provider | Source Name | Priority | Description |
|---|---|---|---|
| Environment Variables | env | Highest | System environment variables with key normalization |
| Properties Files | properties-file-{scope} | Low | application-{profile}.properties per scope |
| YAML Files | yaml-{scope} | Low | application.yml with profile support. Separate lib-conf-yaml module, multiplatform (JVM, Android, iOS, JS, WASM, Linux) |
| Multiplatform Settings | multiplatform-settings-{scope} | Low | Kache/kmp-settings for cross-platform persistence |
| Programmatic Maps | custom name | Configurable | Code-defined MapPropertySource or MutableMapPropertySource |
Properties and YAML files follow the same integration pattern: profile selection via filename suffix, scoped directory structure, and classpath fallback. The YAML module (lib-conf-yaml) uses snakeyaml-engine-kmp for multiplatform YAML parsing and flattens nested YAML keys to dot notation.
EDK (Add Dependency)
| Provider | Provider ID | Priority | Description |
|---|---|---|---|
| Azure App Configuration | azure-app-config | High | Cloud configuration from Azure |
| REST Config Client | rest-config | High | Configuration from a REST API server |
| AWS Secrets Manager | aws-secrets | - | Secret resolution (see Secrets) |
| Azure Key Vault | azure-keyvault-secrets | - | Secret resolution |
| HashiCorp Vault | vault-secrets | - | Secret resolution |
VDX (Database Persistence)
| Provider | Provider ID | Priority | Description |
|---|---|---|---|
| PostgreSQL | postgresql-db | Medium | Persisted settings in PostgreSQL |
| MySQL | mysql-db | Medium | Persisted settings in MySQL |
| SQLite | sqlite-db | Medium | Persisted settings in SQLite |
Auto-Registration
Providers beyond the IDK built-ins use auto-registration. When you add a provider module to your classpath, it automatically integrates with the ConfigService. No wiring code needed; just add the dependency and provide connection details.
dependencies {
// Adding this dependency automatically enables Azure App Configuration
implementation("com.sphereon.edk:lib-conf-azure-app-config:$version")
// Adding this enables database-backed settings
implementation("com.sphereon.vdx:vdx-conf-settings-persistence-postgresql:$version")
}
How It Works
When your application starts, the PropertySourceBootstrap service:
- Discovers all
PropertySourceContributionimplementations via dependency injection - Checks if each contribution is enabled (configuration flag + required config present)
- Filters by
ConfigLevelto register each source at the correct scope (APP, TENANT, or PRINCIPAL) - Registers enabled sources with the appropriate
ConfigServicein priority order
Enabling and Disabling Providers
Each auto-registered provider has a unique ID used to control whether it's active:
| Provider | Provider ID | Enable/Disable Key |
|---|---|---|
| Azure App Config | azure-app-config | config.providers.azure-app-config.enabled |
| REST Config Client | rest-config | config.providers.rest-config.enabled |
| PostgreSQL Database | postgresql-db | config.providers.postgresql-db.enabled |
| MySQL Database | mysql-db | config.providers.mysql-db.enabled |
| SQLite Database | sqlite-db | config.providers.sqlite-db.enabled |
Providers are enabled by default when their module is on the classpath. To disable one:
- Environment Variable
- Properties File
# Disable Azure App Configuration
export CONFIG_PROVIDERS_AZURE_APP_CONFIG_ENABLED=false
# Disable database provider
export CONFIG_PROVIDERS_POSTGRESQL_DB_ENABLED=false
config.providers.azure-app-config.enabled=false
config.providers.postgresql-db.enabled=false
Conditional Enablement
Some providers only enable themselves when required configuration is present. For example, Azure App Configuration only registers if connection details are provided:
# Azure provider enables itself when these are set
export AZURE_APPCONFIG_CONNECTION_STRING=Endpoint=https://myconfig.azconfig.io;...
# Or using endpoint + managed identity
export AZURE_APPCONFIG_ENDPOINT=https://myconfig.azconfig.io
Built-in Providers (IDK)
These providers are always available without adding extra dependencies.
Environment Variables
Reads all system environment variables. Keys are normalized from uppercase-underscore to dot-notation:
API_BASE_URLresolves asapi.base.urlOAUTH2_CLIENT_IDresolves asoauth2.client.id
Environment variables also support property protection prefixes. Prefix a variable with FINAL_ or PROTECTED_ to restrict how lower scopes can use it:
# Cannot be overridden at TENANT or PRINCIPAL scope
export FINAL_DATABASE_HOST=prod-db.example.com
# Cannot be interpolated from lower scopes
export PROTECTED_API_SECRET=sensitive-value
Priority: Highest (always wins)
Properties Files
Reads application-{profile}.properties from the config directory or classpath. Three scoped variants exist:
| Scope | Files loaded | Example path |
|---|---|---|
| APP | application.properties, application-{profile}.properties | config/application-production.properties |
| TENANT | tenant.properties, tenant-{profile}.properties | config/tenant/{tenantId}/tenant-production.properties |
| PRINCIPAL | principal.properties, principal-{profile}.properties | config/tenant/{tenantId}/principal/{principalId}/principal-production.properties |
The base file is always loaded; the profile-specific file is merged on top.
Priority: Low
YAML Files
The lib-conf-yaml module loads application.yml (and profile-specific variants such as application-production.yml) and flattens nested YAML keys to dot notation. It uses snakeyaml-engine-kmp, so it works on all supported Kotlin Multiplatform targets: JVM, Android, iOS, JS, WASM, and Linux. YAML files follow the same conventions as properties files: profile selection via filename suffix and a scoped directory structure with classpath fallback.
api:
base-url: https://api.example.com
timeout-ms: 30000
api:
subscription-key: acme-key-123
Priority: Low
Multiplatform Settings
Uses kmp-settings for cross-platform persistent storage. This is the primary persistence mechanism on mobile platforms (Android SharedPreferences, iOS NSUserDefaults). Three scoped variants cover APP, TENANT, and PRINCIPAL levels.
Priority: Low
Programmatic Maps
Add configuration programmatically using MapPropertySource (read-only) or MutableMapPropertySource (read-write):
val defaults = MapPropertySource(
name = "app-defaults",
source = mapOf(
"http.timeout.ms" to 30000,
"retry.max.attempts" to 3
)
)
configService.addPropertySource(defaults)
Priority: Configurable (defaults to Medium)
Provider Priority
When the same key exists in multiple providers, the highest-priority source wins:
Environment Variable: api.url=https://env.example.com ← WINS
Cloud Config: api.url=https://azure.example.com
Database: api.url=https://db.example.com
Properties File: api.url=https://file.example.com
Priority is controlled by the order value on each PropertySource (lower number = higher priority). The built-in sources use the Order enum:
| Order constant | Priority | Used by |
|---|---|---|
Order.HIGHEST | Highest | Environment variables |
Order.HIGH | High | Cloud providers |
Order.MEDIUM | Medium | Programmatic maps |
Order.LOW | Low | Properties files, YAML files, multiplatform settings |
Order.LOWEST | Lowest | Fallback defaults |
Caching
Different provider types use different caching strategies:
| Provider Type | Cache | Purpose |
|---|---|---|
| Cloud Providers (EDK) | OfflineConfigCache | Persists config to disk for network failure resilience |
| Database Providers (VDX) | SettingsCache (Kache) | In-memory LRU cache with TTL to reduce database queries |
| IDK Resolution Pipeline | SyncConfigSnapshotCache | In-memory snapshot cache for prefix-based queries |
In-Memory Cache
The resolution pipeline can cache resolved values in memory. Cache behaviour is controlled via environment variables:
SPHEREON_CONFIG_CACHE_ENABLED=true
SPHEREON_CONFIG_CACHE_MAX_ENTRIES=1000
SPHEREON_CONFIG_CACHE_EVICTION_POLICY=LRU # LRU, LFU, or FIFO
SPHEREON_CONFIG_CACHE_SNAPSHOT_ENABLED=true
SPHEREON_CONFIG_CACHE_SNAPSHOT_MAX_ENTRIES=200
SPHEREON_CONFIG_CACHE_SNAPSHOT_TTL=1800 # seconds
Offline Cache (EDK)
Cloud providers can persist configuration locally so the application keeps working during network outages. See Offline Cache for details.
Troubleshooting
Provider Not Registering
- Check the module is on the classpath: Verify the dependency is in your build file
- Check the enable flag: Ensure
config.providers.{id}.enabledisn't set tofalse - Check required config: Some providers need connection details to self-enable (e.g.,
secrets.vault.addressfor Vault)
Wrong Value Being Used
- Check provider priority: Higher priority sources override lower ones. Environment variables always win.
- Check key normalization:
api.baseUrl,api.base.url, andAPI_BASE_URLall resolve to the same normalized key - Check protection: A
FINALproperty at APP scope cannot be overridden by a TENANT or PRINCIPAL source
Cloud Provider Failing
- Check credentials: Verify connection strings, API keys, or managed identity setup
- Check network: Ensure firewall allows connections to the cloud service
- Check offline cache: If enabled, cached values are returned during outages