Strong-typed object diffing for dotnet with a compact and readable JSON format.
JsonDiff generates a companion .Diff class for your models at compile-time. It allows you to track changes, reduce network payload, and sync state with System.Text.Json serialization.
Add partial and [JsonDiffClass] to the models you want to track.
[JsonDiffClass]
public partial class UserProfile {
public string Name { get; set; }
public int Level { get; set; }
...var profile = new UserProfile();
var diff = profile.CreateReferenceDiff();
// Modify
profile.Name = "Alice";
profile.Level = 42;
// Calculate changes
diff.TrimIsUnchanged(profile);
var json = JsonSerializer.Serialize(diff);
// {"Name":"Alice","Level":42}UserProfile current = ...
UserProfile.Diff diff = ...
// Reconstruct the previous revision
var previous = diff.ApplyTo(current);
See other examples in Demo
JsonDiff is designed for readability and minimal size. It uses a prefix system for partial updates:
-
Full Replace:
{ "Settings": { "Theme": "Dark" } }
(Overwrites the entire Settings object) -
Partial Patch:
{ "^Settings": { "Theme": "Dark" } }
(Only updates the Theme; keeps other Settings intact)
Note: The ^ prefix tells the parser to perform a partial update rather than a total replacement.
Backwards compatibility, you can start with only a few classes using partial patch and later extend to more classes, old serialized JSON is compatible with the updated code thanks to the prefix system.
Get up and running via NuGet:
dotnet add package SilentOrbit.JsonDiffIncludes both
SilentOrbit.JsonDiff.Abstraction
SilentOrbit.JsonDiff.Generator
Explore
Demo.NuGet
and
Demo.Source
on GitHub.
To check generated code into Source Control (Git), we provide build targets in the Demo.Source.csproj:
- Debug/Release: Standard background source generation.
- GenerateSource: Runs the generator and saves the .cs files to your /Generated folder.
- DebugGenerated: Builds using the saved files (Source Generator disabled).
| Configuration | Source Generation | Save to "Generated" | Build |
|---|---|---|---|
| Debug | Yes | No | Newly generated |
| Release | Yes | No | Newly generated |
| GenerateSource (Debug) | Yes | Yes | Newly generated |
| DebugGenerated | No | No | Previously generated |
| ReleaseGenerated | No | No | Previously generated |
Fine-tune how your diffs are generated using property attributes:
| Attribute | Effect |
|---|---|
| [JsonDiffAlways] | Always include this property in the diff, assume always changed. |
| [JsonDiffIgnore] | Don't include this property in the diff. |
| [JsonDiffImmutable] | Treat the property as a single value, never attempt a partial patch. |
| [JsonDiffFull] | Force a deep copy of the value when a change is detected. |