Configuration System
Hierarchical configuration management with environment overrides, caching, and type-safe access.
JSON ConfigEnvironmentDot NotationCachingType Safety
Quick Start
Basic Usage
dart
// Basic configuration access
final appName = Khadem.config.get<String>('app.name');
final port = Khadem.config.get<int>('app.port', 3000);
final debug = Khadem.config.get<bool>('app.debug', false);
// Environment variables
final apiKey = Khadem.env.get('API_KEY');
final dbUrl = Khadem.env.getOrDefault('DATABASE_URL', 'sqlite:memory:');
💡 Note: Configuration is automatically loaded via service provider
⚡ Tip: Use dot notation like 'app.database.host'
for nested access
Configuration Structure
Directory Layout
bash
config/
├── app.json # Base application config
├── database.json # Base database config
├── cache.json # Base cache config
└── development/ # Environment-specific overrides
├── app.json # Development app overrides
├── database.json # Development database overrides
└── cache.json # Development cache overrides
Base Configuration
Default values for all environments
Environment Overrides
Environment-specific values that override base config
json
{
"name": "KhademApp",
"env": "production",
"port": 8080,
"debug": false,
"database": {
"host": "localhost",
"port": 5432,
"database": "khadem"
}
}
json
{
"env": "development",
"port": 3000,
"debug": true,
"database": {
"host": "localhost",
"port": 5432,
"database": "khadem_dev"
}
}
Core Operations
dart
// Get values with type safety
final appName = Khadem.config.get<String>('app.name');
final port = Khadem.config.get<int>('app.port');
final debug = Khadem.config.get<bool>('app.debug');
// Get with defaults
final timeout = Khadem.config.get<int>('app.timeout', 30);
final host = Khadem.config.get<String>('database.host', 'localhost');
// Check existence
if (Khadem.config.has('database.url')) {
final url = Khadem.config.get<String>('database.url');
}
dart
// Set runtime values
Khadem.config.set('app.maintenance', true);
Khadem.config.set('cache.ttl', 3600);
// Nested object access
final dbHost = Khadem.config.get<String>('database.host');
final dbPort = Khadem.config.get<int>('database.port');
// Get entire sections
final dbConfig = Khadem.config.section('database');
final allConfig = Khadem.config.all();
// Reload configuration
Khadem.config.reload();
⚠️ Important Notes
- • Configuration files are cached with TTL for performance
- • Environment overrides are merged with base configuration
- • Use
reload()
to refresh configuration from disk - • Runtime changes don't persist to files
Environment Variables
dart
// Environment variable access
final apiKey = Khadem.env.get('API_KEY');
final dbUrl = Khadem.env.getOrDefault('DATABASE_URL', 'sqlite:memory:');
// Type-safe environment access
final port = Khadem.env.getInt('PORT', defaultValue: 3000);
final debug = Khadem.env.getBool('DEBUG', defaultValue: false);
final rate = Khadem.env.getDouble('EXCHANGE_RATE', defaultValue: 1.0);
// List values
final hosts = Khadem.env.getList('ALLOWED_HOSTS', separator: ',');
final paths = Khadem.env.getList('PATHS', separator: ';');
// Set environment values
Khadem.env.set('TEMP_VAR', 'temporary_value');
.env File Support
env
# Application settings
APP_NAME=MyApp
APP_VERSION=1.0.0
DEBUG=true
PORT=3000
# Database configuration
DATABASE_URL="postgresql://user:pass@localhost:5432/db"
# Export statements supported
export REDIS_URL=redis://localhost:6379
# Variable substitution
API_BASE_URL=http://localhost:$PORT
FULL_NAME="${APP_NAME} v${APP_VERSION}"
# List values
ALLOWED_HOSTS=localhost,127.0.0.1,::1
Type-Safe Access
dart
// String values
final name = Khadem.config.get<String>('app.name');
final url = Khadem.config.get<String>('database.url', 'sqlite:memory:');
// Numeric values
final port = Khadem.config.get<int>('app.port', 3000);
final timeout = Khadem.config.get<double>('app.timeout', 30.0);
// Boolean values
final debug = Khadem.config.get<bool>('app.debug', false);
final enabled = Khadem.config.get<bool>('feature.enabled', true);
// List values (from environment)
final hosts = Khadem.env.getList('ALLOWED_HOSTS');
final paths = Khadem.env.getList('SEARCH_PATHS', separator: ';');
// Environment with type conversion
final maxConn = Khadem.env.getInt('MAX_CONNECTIONS', defaultValue: 10);
final rateLimit = Khadem.env.getDouble('RATE_LIMIT', defaultValue: 100.0);
Supported Types
- •
String
- Text values - •
int
- Integer numbers - •
double
- Floating point numbers - •
bool
- Boolean values (true/false) - •
List<String>
- String arrays - •
Map<String, dynamic>
- Nested objects
Runtime Configuration
dart
// Runtime configuration changes
Khadem.config.set('app.maintenance', true);
Khadem.config.set('cache.enabled', false);
Khadem.config.set('database.connections.max', 50);
// Dynamic feature flags
class FeatureFlags {
static bool isEnabled(String feature) {
return Khadem.config.get<bool>('features.$feature', false);
}
static void enable(String feature) {
Khadem.config.set('features.$feature', true);
}
static void disable(String feature) {
Khadem.config.set('features.$feature', false);
}
}
// Usage
if (FeatureFlags.isEnabled('new_ui')) {
// Show new UI
}
FeatureFlags.enable('beta_feature');
Use Cases
- • Dynamic feature flags
- • Runtime service configuration
- • Testing environment setup
- • Administrative overrides
Configuration Sections
dart
// Get entire configuration sections
final appConfig = Khadem.config.section('app');
final dbConfig = Khadem.config.section('database');
final cacheConfig = Khadem.config.section('cache');
// Work with section data
if (appConfig != null) {
print('App Name: ${appConfig['name']}');
print('Debug Mode: ${appConfig['debug']}');
}
// Get all configuration
final allConfig = Khadem.config.all();
for (final section in allConfig.keys) {
print('Section: $section');
print('Values: ${allConfig[section]}');
}
// Check configuration existence
final hasDatabase = Khadem.config.has('database');
final hasCache = Khadem.config.has('cache.host');
final hasFeature = Khadem.config.has('features.new_ui');
Section Operations
- •
section('name')
- Get entire section as map - •
all()
- Get all configuration data - •
has('key')
- Check if key exists - •
reload()
- Refresh from disk
Registry-Based Loading
dart
// Load configuration from code
Khadem.loadConfigs({
'app': {
'name': 'MyApp',
'version': '1.0.0',
'debug': true
},
'database': {
'host': 'localhost',
'port': 5432,
'database': 'myapp'
},
'cache': {
'driver': 'memory',
'ttl': 3600
}
});
// Or load single sections
final customConfig = {
'api': {
'base_url': 'https://api.example.com',
'timeout': 30,
'retries': 3
}
};
Khadem.config.loadFromRegistry(customConfig);
When to Use Registry
- • Programmatic configuration setup
- • Testing with mock configurations
- • Dynamic configuration generation
- • Configuration from external sources
Best Practices
✅ Do's
- • Use descriptive, namespaced keys
- • Provide sensible default values
- • Use environment-specific overrides
- • Validate configuration on startup
- • Document configuration options
- • Use type-safe access methods
- • Cache expensive configuration lookups
❌ Don'ts
- • Don't hardcode configuration values
- • Don't access config in performance-critical loops
- • Don't store sensitive data in config files
- • Don't modify config files at runtime
- • Don't use config for frequently changing data
- • Don't skip validation of required config
- • Don't use generic types without defaults
Common Patterns
Configuration Validation
Validate required configuration on startup
dart
// Configuration validation on startup
class ConfigValidator {
static void validate() {
final missing = <String>[];
// Required configuration
if (!Khadem.config.has('app.name')) {
missing.add('app.name');
}
if (!Khadem.config.has('database.host')) {
missing.add('database.host');
}
// Required environment variables
final missingEnv = Khadem.env.validateRequired([
'DATABASE_URL',
'API_KEY',
'JWT_SECRET'
]);
missing.addAll(missingEnv);
if (missing.isNotEmpty) {
throw Exception('Missing required configuration: $missing');
}
// Validate value ranges
final port = Khadem.config.get<int>('app.port', 3000);
if (port < 1000 || port > 65535) {
throw Exception('Invalid port number: $port');
}
}
}
// Call during app startup
void main() {
ConfigValidator.validate();
// Continue with app initialization
}
Feature Flags
Runtime feature toggles
dart
// Feature flags implementation
class FeatureManager {
static const String _prefix = 'features';
static bool isEnabled(String feature) {
return Khadem.config.get<bool>('$_prefix.$feature', false);
}
static void enable(String feature) {
Khadem.config.set('$_prefix.$feature', true);
_logFeatureChange(feature, true);
}
static void disable(String feature) {
Khadem.config.set('$_prefix.$feature', false);
_logFeatureChange(feature, false);
}
static List<String> getEnabledFeatures() {
final features = Khadem.config.section(_prefix);
if (features == null) return [];
return features.entries
.where((entry) => entry.value == true)
.map((entry) => entry.key)
.toList();
}
static void _logFeatureChange(String feature, bool enabled) {
Khadem.logger.info(
'Feature flag changed: $feature = $enabled'
);
}
}
// Usage throughout the app
if (FeatureManager.isEnabled('new_dashboard')) {
return NewDashboard();
} else {
return OldDashboard();
}
Environment-Specific Config
Different settings per environment
dart
// Environment-specific configuration
class EnvironmentConfig {
static String get environment {
return Khadem.config.get<String>('app.env', 'production');
}
static bool get isDevelopment {
return environment == 'development';
}
static bool get isProduction {
return environment == 'production';
}
static bool get isTesting {
return environment == 'testing';
}
static String get databaseName {
final baseName = Khadem.config.get<String>('database.name', 'app');
return isTesting ? '${baseName}_test' : baseName;
}
static int get cacheTtl {
return isDevelopment ? 60 : 3600; // 1 min dev, 1 hour prod
}
static bool get enableDebugLogging {
return isDevelopment || Khadem.config.get<bool>('app.debug', false);
}
static String get logLevel {
return isDevelopment ? 'DEBUG' : 'INFO';
}
}
// Usage
if (EnvironmentConfig.isDevelopment) {
// Development-specific code
}
final dbName = EnvironmentConfig.databaseName;
final cacheTtl = EnvironmentConfig.cacheTtl;