Structured diff for JSON configuration files — detect added, removed, changed, and unchanged keys.
dotnet add package Philiprehberger.ConfigDiffStructured diff for JSON configuration files — detect added, removed, changed, and unchanged keys.
dotnet add package Philiprehberger.ConfigDiff
using Philiprehberger.ConfigDiff;
var jsonA = """
{
"Logging": { "Level": "Warning" },
"ConnectionStrings": { "Default": "Server=old" },
"FeatureFlag": false
}
""";
var jsonB = """
{
"Logging": { "Level": "Information" },
"ConnectionStrings": { "Default": "Server=old" },
"NewSetting": "hello"
}
""";
ConfigDiffResult diff = ConfigComparer.Compare(jsonA, jsonB);
foreach (var key in diff.Added)
Console.WriteLine($"+ {key}");
foreach (var key in diff.Removed)
Console.WriteLine($"- {key}");
foreach (var change in diff.Changed)
Console.WriteLine($"~ {change.Path}: '{change.OldValue}' -> '{change.NewValue}'");
// Output:
// + NewSetting
// - FeatureFlag
// ~ Logging.Level: 'Warning' -> 'Information'
var diff = ConfigComparer.CompareFiles("appsettings.json", "appsettings.Production.json");
using var streamA = File.OpenRead("appsettings.json");
using var streamB = File.OpenRead("appsettings.Production.json");
var diff = ConfigComparer.Compare(streamA, streamB);
Use ignorePaths to exclude specific keys from the comparison. Supports exact matches and wildcard prefix matches with .*:
var diff = ConfigComparer.Compare(jsonA, jsonB, ignorePaths: new[]
{
"Logging.*", // ignore everything under Logging
"ConnectionStrings.*" // ignore everything under ConnectionStrings
});
// Only NewSetting and FeatureFlag will appear in the result
Changed entries include both the old and new values via the ConfigChange record:
foreach (var change in diff.Changed)
{
Console.WriteLine($"{change.Path}: {change.OldValue} -> {change.NewValue}");
}
ConfigComparer| Method | Description |
|---|---|
Compare(string jsonA, string jsonB, IEnumerable<string>? ignorePaths = null) | Diff two JSON strings |
CompareFiles(string pathA, string pathB, IEnumerable<string>? ignorePaths = null) | Read files from disk and diff them |
Compare(Stream streamA, Stream streamB, IEnumerable<string>? ignorePaths = null) | Read streams and diff them |
ConfigDiffResult| Property | Type | Description |
|---|---|---|
Added | IReadOnlyList<string> | Keys present in B but not in A |
Removed | IReadOnlyList<string> | Keys present in A but not in B |
Changed | IReadOnlyList<ConfigChange> | Keys present in both with different values |
Unchanged | IReadOnlyList<string> | Keys with identical values |
ConfigChange| Property | Type | Description |
|---|---|---|
Path | string | Dot-notation key path |
OldValue | string? | Value in A |
NewValue | string? | Value in B |
dotnet build src/Philiprehberger.ConfigDiff.csproj --configuration Release
If you find this project useful: