Getting Started
Install
Pick the package that matches your scenario — each one includes everything above it:
dotnet add package Cocoar.Configuration # Core library (console apps, no DI)
dotnet add package Cocoar.Configuration.DI # ↑ + Microsoft.Extensions.DI integration
dotnet add package Cocoar.Configuration.AspNetCore # ↑ + health endpoints, feature flag endpointsYou only need one of these — install the highest one you need.
Optional packages for additional providers:
dotnet add package Cocoar.Configuration.Http # Remote config via HTTP
dotnet add package Cocoar.Configuration.MicrosoftAdapter # Bridge existing IConfigurationYour First Configuration
1. Define a configuration class
public class AppSettings
{
public string AppName { get; set; } = "MyApp";
public int MaxRetries { get; set; } = 3;
public bool EnableLogging { get; set; } = true;
}No base class, no attributes, no interfaces. Just a plain C# class.
2. Create a JSON config file
appsettings.json:
{
"AppName": "My Application",
"MaxRetries": 5,
"EnableLogging": true
}3. Wire it up
var builder = WebApplication.CreateBuilder(args);
builder.AddCocoarConfiguration(c => c
.UseConfiguration(rule => [
rule.For<AppSettings>().FromFile("appsettings.json")
]));
var app = builder.Build();
// Inject directly — no IOptions<T> wrapper
app.MapGet("/settings", (AppSettings settings) => new
{
settings.AppName,
settings.MaxRetries
});
app.Run();using var manager = ConfigManager.Create(c => c
.UseConfiguration(rule => [
rule.For<AppSettings>().FromFile("appsettings.json")
]));
var settings = manager.GetConfig<AppSettings>();
Console.WriteLine($"App: {settings.AppName}, Retries: {settings.MaxRetries}");That's it. AppSettings is loaded and ready to inject.
Layering Multiple Sources
The real power comes from layering. Rules execute in order — last write wins:
builder.AddCocoarConfiguration(c => c
.UseConfiguration(rule => [
rule.For<AppSettings>().FromFile("appsettings.json"), // Base
rule.For<AppSettings>().FromFile("appsettings.Production.json"), // Override per environment
rule.For<AppSettings>().FromEnvironment("APP_"), // Override from env vars
]));With this setup:
appsettings.jsonprovides defaultsappsettings.Production.jsonoverrides what it sets- Environment variables like
APP_MaxRetries=10override everything
Properties merge at the JSON level. A later rule only overrides the properties it defines — everything else keeps the value from earlier rules.
Live Reloading
When a file changes on disk, configuration updates automatically. Subscribe to changes:
public class NotificationService(IReactiveConfig<AppSettings> config)
{
public void Start()
{
// Called immediately with current value, then on every change
config.Subscribe(settings =>
{
Console.WriteLine($"Config updated: MaxRetries={settings.MaxRetries}");
});
}
}IReactiveConfig<T> is automatically registered in DI for every configuration type.
What Happens Under the Hood
When you call ConfigManager.Create() or AddCocoarConfiguration():
- Rules are evaluated in order — each provider fetches its data (reads file, scans env vars, etc.)
- JSON is merged — later rules overlay earlier ones, property by property
- Types are deserialized — the merged JSON becomes your strongly-typed C# object
- Change detection starts — file watchers, polling timers, etc. monitor for changes
- Updates are atomic — when a source changes, the full recompute runs and all subscribers get the new snapshot at once
Next Steps
- Rules & Layering — Deep dive into the rule system
- Providers — All available configuration sources
- Reactive Updates — Subscribe to live config changes
- DI Integration — Lifetimes, type exposure, ASP.NET Core setup