Guide
C# records for the .NET JSON serializer from sample JSON
Visual Studio’s Paste JSON as Classes produces older-style classes without attributes or nullability. Modern .NET code usually wants records, System.Text.Json attributes and nullable reference types. This generator writes exactly that from a sample, so a response from any API can be deserialised in one line.
Built for the .NET serializer
The output targets System.Text.Json, the serializer built into .NET Core 3.0 and later and the default in ASP.NET Core. It is faster than Newtonsoft.Json and needs no package. Each property carries [JsonPropertyName("…")] with the original key, so the PascalCase C# names do not depend on serializer options.
Records with init-only properties
Every object shape becomes a public sealed record with { get; init; } properties. Records give value equality, so two orders with the same data compare equal, which makes tests simpler; init-only setters keep the objects immutable after deserialisation while still allowing object initialisers in your own code.
required and nullable
Properties present with a value in every sample are marked required, a C# 11 feature: the compiler insists they are set when you create the object yourself, and from .NET 7 System.Text.Json reports a missing required property as an error instead of leaving a default. Optional and nullable fields use nullable types such as string? and long? and are not required, so enable nullable reference types (<Nullable>enable</Nullable>) to get warnings where your code forgets to check them.
Types
Whole numbers map to long and decimals to double, booleans to bool, arrays to List<T>. Fields whose type varies or that were always null become JsonElement, which you can inspect with ValueKind. With date types on, ISO 8601 timestamps become DateTimeOffset, which keeps the time-zone offset.
Using the records
In ASP.NET Core minimal APIs, declare the record as a parameter and the body is bound for you: app.MapPost("/users", (User user) => …). With HttpClient, GetFromJsonAsync<User> and ReadFromJsonAsync<User> deserialise in one call. For source generation and trimming in AOT apps, add a JsonSerializerContext that lists the root record.
A worked example
The sample user becomes four records: User, Order, Item and Address. The order’s key order_id becomes [JsonPropertyName("order_id")] public required long OrderId { get; init; }, while the coupon that only one order has becomes public string? Coupon { get; init; } without required.
Older .NET versions
required needs C# 11 and .NET 7; for earlier versions delete the keyword. For projects on Newtonsoft.Json, replace the attribute with [JsonProperty("…")] and change the using directives. File-scoped namespaces need C# 10; switch to a block namespace for older compilers.
Collections and defaults
List<T> properties are required when every sample had the array, even if some arrays were empty, so code can iterate without null checks. If you prefer an empty list when the key is missing, drop required and initialise the property: public List<Item> Items { get; init; } = []; with C# 12 collection expressions.
Naming the root type
The root record takes the name you type, and nested records are named after their keys in singular form. Rename them freely in your editor; the attributes keep the JSON mapping intact, so renaming a C# type never changes the wire format.
Related tools
Generate Java records with JSON to Java or TypeScript for the front end with JSON to TypeScript, translate curl examples into C# HttpClient code with cURL to Code, or inspect the payload in the JSON Formatter.
Checked against the current version of the JSON to C# Record on .

