JSON serialization is a core part of modern .NET applications. Whether you're building REST APIs, microservices, background services, or message-driven systems, converting objects to and from JSON happens thousands—or even millions—of times every day.
A small improvement in serialization performance can reduce CPU usage, memory allocations, and response latency under high traffic. .NET provides several serialization approaches, each with different trade-offs in speed, memory consumption, and flexibility.
In this article, you'll compare the most common JSON serialization options in .NET 11, implement each approach, and learn how to benchmark them correctly without relying on fabricated performance numbers.
Note: This article explains implementation and benchmark methodology. Since the research brief does not include measured benchmark data or hardware specifications, no performance numbers are presented.
JSON Serialization in .NET
Serialization converts a .NET object into JSON.
Product Object
│
▼
JSON Serializer
│
▼
{
"id": 1,
"name": "Laptop"
}
Deserialization performs the reverse operation by converting JSON back into .NET objects.
Available Serialization Options
Modern .NET applications typically use one of the following approaches.
| Serializer | Performance | Memory Usage | Flexibility |
|---|---|---|---|
| System.Text.Json | High | Low | Good |
| System.Text.Json Source Generation | Very High | Very Low | Moderate |
| Newtonsoft.Json | Good | Moderate | Excellent |
The right choice depends on your application's requirements.
Sample Model
We'll use the following model throughout the examples.
public class Product
{
public int Id { get; set; }
public string Name { get; set; } = "";
public decimal Price { get; set; }
public bool InStock { get; set; }
}
Using System.Text.Json
System.Text.Json is included with .NET and is the default serializer used by ASP.NET Core.
Serialize an object:
using System.Text.Json;
var product = new Product
{
Id = 1,
Name = "Laptop",
Price = 999,
InStock = true
};
string json =
JsonSerializer.Serialize(product);
Deserialize:
var product =
JsonSerializer.Deserialize<Product>(json);
Why Use It?
Advantages include:
High performance
Low memory allocations
Built into .NET
No external dependency
Native ASP.NET Core integration
It is the preferred choice for most new applications.
Using Source Generation
Source generation reduces runtime reflection by generating serialization code during compilation.
Create a context.
using System.Text.Json.Serialization;
[JsonSerializable(typeof(Product))]
public partial class ProductContext
: JsonSerializerContext
{
}
Serialize using the generated context.
string json =
JsonSerializer.Serialize(
product,
ProductContext.Default.Product);
Benefits
Source generation can reduce startup overhead and runtime allocations, particularly in applications that repeatedly serialize known types.
It is especially useful for:
Native AOT
High-throughput APIs
Microservices
Background processing
Using Newtonsoft.Json
Install the package.
dotnet add package Newtonsoft.Json
Serialize:
using Newtonsoft.Json;
string json =
JsonConvert.SerializeObject(product);
Deserialize:
var product =
JsonConvert.DeserializeObject<Product>(json);
When Should You Use It?
Newtonsoft.Json remains useful for scenarios involving:
Advanced converters
Dynamic JSON
LINQ to JSON
Legacy applications
Extensive customization
Many existing enterprise applications still depend on its mature feature set.
ASP.NET Core Integration
System.Text.Json is enabled by default.
To use Newtonsoft.Json:
builder.Services
.AddControllers()
.AddNewtonsoftJson();
Choose one serializer consistently throughout your application unless there is a specific compatibility requirement.
Source Generation Workflow
A simplified workflow looks like this:
Model
│
▼
Source Generator
│
Generated Serialization Code
│
▼
Runtime Serialization
Generating serialization code at build time reduces work performed at runtime.
Benchmarking Methodology
The research brief requests serializer benchmarking but does not provide benchmark results or hardware details. Instead of presenting unsupported numbers, use the following methodology.
Test Environment
Keep the following consistent:
.NET SDK version
Operating system
Hardware
Build configuration
Garbage collector mode
Run benchmarks in Release mode.
Test Scenarios
Evaluate multiple workloads.
Small objects:
Product
Large collections:
List<Product>
Complex nested objects.
Large JSON payloads.
Serialization and deserialization should both be measured independently.
BenchmarkDotNet Setup
Install BenchmarkDotNet.
dotnet add package BenchmarkDotNet
Create a benchmark class.
using BenchmarkDotNet.Attributes;
[MemoryDiagnoser]
public class SerializationBenchmark
{
private readonly Product _product =
new()
{
Id = 1,
Name = "Laptop",
Price = 999
};
[Benchmark]
public string SystemTextJson()
=> JsonSerializer.Serialize(_product);
[Benchmark]
public string Newtonsoft()
=> JsonConvert.SerializeObject(_product);
}

Join the conversation! Your thoughts help the community grow.