A high-performance, multi-source configuration library for .NET. Supports JSON, YAML, TOML, INI, XML, environment variables, command-line arguments, user secrets, and custom sources. Binds to strongly-typed options with DataAnnotations validation, custom type converters, configuration profiles, hot-reload capability, zero-copy reads, and optional hot-reload. Built for production: fast, reliable, and secure.
- Multiple Formats — JSON, YAML, TOML, INI, XML with automatic format detection
- Multi-Source Loading — Environment variables, command-line arguments, user secrets, in-memory dictionaries, files, HTTP endpoints, and custom sources with override priority by registration order
- Strongly-Typed Binding — Bind flat configuration to POCO classes with nested object and collection support
- Validation — Type checking, DataAnnotations support, and error reporting during binding with clear paths to configuration errors
- Custom Type Converters — Extend type conversion for custom types (Uri, IPAddress, etc.)
- Configuration Profiles — Environment-specific settings (development, staging, production) with auto-detection
- Merging Strategies — Control how multiple sources combine: last-wins, first-wins, merge, or strict
- Hot-Reload — FileSystemWatcher integration for automatic configuration reloading with change notifications
- Remote Configuration — Load configuration from HTTP endpoints with optional polling for cloud-native architectures
- Configuration Export — Serialize configuration to JSON or YAML for debugging and auditing
- Lazy Loading — Defer source initialization until first access with optional timeouts for performance optimization
- Async-First Design — Async load paths with
ValueTask<T>for performance; sync paths also available - Zero-Copy Reads — Configuration cached after loading; reads are lock-free and allocation-free
- Extensible — Custom sources and parsers via simple interfaces
- Cross-Platform — Works on Windows, Linux, and macOS
dotnet add package JG.ConfigKitDefine a configuration class:
public class DatabaseSettings
{
public string Host { get; set; } = "localhost";
public int Port { get; set; } = 5432;
public string Username { get; set; } = "";
public string Password { get; set; } = "";
}Register and use in dependency injection:
var services = new ServiceCollection();
services
.AddConfiguration()
.AddJsonFile("appsettings.json")
.AddEnvironmentVariables("MYAPP")
.Build<DatabaseSettings>();
var serviceProvider = services.BuildServiceProvider();
var dbSettings = serviceProvider.GetRequiredService<DatabaseSettings>();
Console.WriteLine($"Connecting to {dbSettings.Host}:{dbSettings.Port}");Environment variables are matched case-insensitively with underscores converted to dots:
export MYAPP_HOST=prod.db.example.com
export MYAPP_PORT=5433
# Binds to Host="prod.db.example.com", Port=5433.AddJsonFile("appsettings.json")
.AddJsonFile("appsettings.local.json", isOptional: true) // Skip if missing
.AddJsonFile("appsettings.prod.json", isOptional: true, enableHotReload: true).AddYamlFile("config.yaml", enableHotReload: true)
.AddYamlFile("config.local.yaml", isOptional: true).AddTomlFile("config.toml")
.AddTomlFile("config.local.toml", isOptional: true).AddIniFile("config.ini")
.AddIniFile("config.local.ini", isOptional: true, enableHotReload: true).AddXmlFile("config.xml")
.AddXmlFile("config.local.xml", isOptional: true).AddEnvironmentVariables("MYAPP")Environment variables with the prefix (followed by underscore) are included. Underscores become dots:
MYAPP_DATABASE_HOST=localhost # → database.host
MYAPP_DEBUG=true # → debug.AddCommandLineArguments(args)Arguments support three formats:
--key=value # Direct assignment
--key value # Space-separated
-k value # Short form
--flag # Boolean flags (→ "true").AddUserSecrets<Program>()Loads from ~/.microsoft/usersecrets/{UserSecretsId}/secrets.json. Perfect for local development secrets without committing to source control.
.AddMemory(new Dictionary<string, string>
{
{ "database.host", "localhost" },
{ "database.port", "5432" }
})Implement IConfigSource:
public class CustomSource : IConfigSource
{
public string Name => "Custom";
public IReadOnlyDictionary<string, string> Load()
{
return new Dictionary<string, string>
{
{ "key", "value" }
};
}
public ValueTask<IReadOnlyDictionary<string, string>> LoadAsync(CancellationToken cancellationToken = default)
{
return new ValueTask<IReadOnlyDictionary<string, string>>(Load());
}
}
// Register
.AddSource(new CustomSource())Configuration is bound to public properties. Supported types:
- String, bool, int, long, float, double, decimal
- Guid, DateTime, TimeSpan
- Enums (case-insensitive)
- Nullable types
- Custom types with
IConfigValueConverter<T> - Collections (arrays, lists) via array indexing
public class AppSettings
{
public DatabaseSettings Database { get; set; } = new();
public LogSettings Log { get; set; } = new();
public Uri ApiEndpoint { get; set; } = null!;
}
public class DatabaseSettings
{
public string Host { get; set; } = "localhost";
public int Port { get; set; } = 5432;
}
public class LogSettings
{
public LogLevel Level { get; set; } = LogLevel.Info;
}
public enum LogLevel { Debug, Info, Warning, Error }Convert custom types like Uri, IPAddress, or domain-specific types:
public class UriConverter : IConfigValueConverter<Uri>
{
public Uri Convert(string? value)
{
if (string.IsNullOrEmpty(value))
throw new ArgumentException("URI cannot be empty");
return new Uri(value);
}
}
// Register
var binder = new EnhancedReflectionConfigBinder<AppSettings>();
binder.RegisterConverter<Uri>(new UriConverter());Validate configuration using standard .NET attributes:
public class AppSettings
{
[Required(ErrorMessage = "API key is required")]
public string? ApiKey { get; set; }
[Range(1, 65535, ErrorMessage = "Port must be between 1 and 65535")]
public int Port { get; set; }
[EmailAddress(ErrorMessage = "Invalid email format")]
public string? AdminEmail { get; set; }
[Url(ErrorMessage = "Invalid URL format")]
public string? ApiUrl { get; set; }
}Validation errors are reported during binding with clear messages and configuration paths.
Use environment-specific settings:
services
.AddConfiguration()
.WithAutoProfile() // Auto-detect from ASPNETCORE_ENVIRONMENT
.AddJsonFile("appsettings.json")
.AddJsonFile("appsettings.{profile}.json") // development, staging, production
.AddEnvironmentVariables("MYAPP")
.Build<AppSettings>();Or set profile explicitly:
.WithProfile("production")Automatically reload configuration when files change:
services
.AddConfiguration()
.AddJsonFile("config.json", enableHotReload: true)
.AddYamlFile("settings.yaml", enableHotReload: true)
.Build<AppSettings>();
// Subscribe to changes
var hotReload = serviceProvider.GetRequiredService<HotReloadFileSource>();
hotReload.OnChange(newConfig =>
{
Console.WriteLine("Configuration reloaded!");
});Load configuration from HTTP endpoints with optional automatic polling:
services
.AddConfiguration()
.AddJsonFile("appsettings.json")
// Load from remote server, polling every 60 seconds
.AddHttpSource(
new Uri("https://config.example.com/api/settings"),
new JsonConfigParser(),
pollIntervalSeconds: 60)
.Build<AppSettings>();Control how multiple sources are combined:
services
.AddConfiguration()
.WithMergeStrategy(MergeStrategy.FirstWins) // First source wins
.AddJsonFile("defaults.json")
.AddJsonFile("overrides.json")
.Build<AppSettings>();Available strategies:
LastWins(default) — Later sources override earlier onesFirstWins— First source to define a key winsMerge— Combine all sources; error on conflicts with different valuesThrow— Error if any key appears in multiple sources
Defer source loading until first access for improved startup performance:
services
.AddConfiguration()
.AddJsonFile("appsettings.json")
// Lazy-load from HTTP with 30-second timeout
.AddLazySource(
new HttpConfigSource(new Uri("https://config.example.com/settings"), new JsonConfigParser()),
timeoutSeconds: 30)
.Build<AppSettings>();Export loaded configuration to JSON or YAML for debugging:
var configBuilder = services.AddConfiguration()
.AddJsonFile("appsettings.json")
.AddEnvironmentVariables("MYAPP");
// Export for inspection
var jsonConfig = configBuilder.ExportAsJson(indent: true);
var yamlConfig = configBuilder.ExportAsYaml();
Console.WriteLine(jsonConfig);
File.WriteAllText("exported-config.json", jsonConfig);Provide fallback values that can be overridden by other sources:
services
.AddConfiguration()
.AddDefaults(new Dictionary<string, string>
{
{ "database.host", "localhost" },
{ "database.port", "5432" },
{ "logging.level", "Info" }
})
.AddJsonFile("appsettings.json", isOptional: true)
.AddEnvironmentVariables("MYAPP")
.Build<AppSettings>();Defaults are applied first, so any later source can override them.
Register and reuse common configurations across your application:
// Register presets during setup
services
.AddConfiguration()
.RegisterPreset("development", new Dictionary<string, string>
{
{ "database.host", "localhost" },
{ "logging.level", "Debug" },
{ "features.strict-validation", "true" }
})
.RegisterPreset("production", new Dictionary<string, string>
{
{ "database.host", "prod-db.example.com" },
{ "logging.level", "Error" },
{ "features.strict-validation", "false" }
})
// Load the appropriate preset based on environment
.UsePreset(Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") ?? "development")
.AddJsonFile("appsettings.json", isOptional: true)
.Build<AppSettings>();Or use presets with profiles:
services
.AddConfiguration()
.RegisterPreset("dev", devDefaults)
.RegisterPreset("prod", prodDefaults)
.WithAutoProfile()
.UsePreset(builder.CurrentProfile ?? "dev") // Load preset matching profile
.AddJsonFile($"appsettings.{profile}.json", isOptional: true)
.Build<AppSettings>();For more information, see:
- Getting Started Guide — Quick start and common patterns
- API Reference — Complete API documentation
- Advanced Usage — Complex scenarios and best practices
Contributions are welcome! Please feel free to submit a Pull Request.
Licensed under the Apache License 2.0. See LICENSE for details.
Ready to get started? Install via NuGet and check out the getting started guide.