System.Text.Json vs Newtonsoft.Json in 2026 (Still Relevant?)

The debate around System.Text.Json vs Newtonsoft.Json has been simmering since Microsoft introduced its built-in JSON library in .NET Core 3.0. Fast-forward to 2026, and developers are still asking: is Newtonsoft.Json even worth considering, or has System.Text.Json completely taken over? In this post, we’ll cut through the noise with real benchmarks, practical code, and clear guidance on when to use each library in modern .NET applications.
Table of Contents
- A Quick History: How We Got Here
- Performance: System.Text.Json vs Newtonsoft.Json
- Feature Comparison: Where Newtonsoft.Json Still Has the Edge
- System.Text.Json Advanced Features in .NET 8 and .NET 9
- Practical Migration: Moving from Newtonsoft.Json to System.Text.Json
- Security Considerations
- Testing JSON Serialization Behavior
- When to Still Use Newtonsoft.Json in 2026
- Quick Decision Guide
- Conclusion
A Quick History: How We Got Here
Newtonsoft.Json (Json.NET) was the de facto standard for JSON serialization in the .NET ecosystem for well over a decade. James Newton-King’s library offered incredible flexibility — custom converters, contract resolvers, dynamic serialization, and more. It became so popular that it was among the most downloaded NuGet packages of all time.
Then, with .NET Core 3.0 in 2019, Microsoft shipped System.Text.Json as a high-performance, allocation-friendly alternative built right into the runtime. The motivation was clear: reduce allocations on the hot path, improve throughput for ASP.NET Core APIs, and eliminate a heavyweight third-party dependency from the default stack. By 2026, with .NET 9 and .NET 10 in the picture, the gap has narrowed dramatically — but it hasn’t fully closed.
If you’re working on performance-critical services or looking at Native AOT compilation in .NET 9, the choice of JSON library can directly impact binary size and startup time — making this comparison more relevant than ever.
Performance: System.Text.Json vs Newtonsoft.Json
Performance is where System.Text.Json vs Newtonsoft.Json shows the sharpest contrast. System.Text.Json was designed from the ground up to minimize heap allocations by working with Span<T> and ReadOnlySpan<byte> internally. Newtonsoft.Json, being older, does not benefit from these modern runtime primitives.
Typical benchmarks (BenchmarkDotNet, .NET 9) show System.Text.Json is roughly 2–3x faster for serialization and uses 40–60% less memory on average for simple POCO objects. For high-throughput APIs handling thousands of requests per second, this is a meaningful difference. Check the official Microsoft docs for the most up-to-date benchmark data: System.Text.Json overview on MSDN.
Serialization Benchmark Example
// Model
public class Product
{
public int Id { get; set; }
public string Name { get; set; } = string.Empty;
public decimal Price { get; set; }
public DateTime CreatedAt { get; set; }
}
// System.Text.Json serialization
using System.Text.Json;
var product = new Product { Id = 1, Name = "Widget", Price = 9.99m, CreatedAt = DateTime.UtcNow };
string json = JsonSerializer.Serialize(product);
Product? deserialized = JsonSerializer.Deserialize<Product>(json);
// Newtonsoft.Json serialization
using Newtonsoft.Json;
string jsonNewton = JsonConvert.SerializeObject(product);
Product? deserializedNewton = JsonConvert.DeserializeObject<Product>(jsonNewton);
Feature Comparison: Where Newtonsoft.Json Still Has the Edge
System.Text.Json has improved significantly over the years, but Newtonsoft.Json still wins in certain areas, particularly when dealing with complex legacy scenarios.
1. Handling of Reference Loops
Newtonsoft.Json has long supported circular reference handling via ReferenceLoopHandling.Ignore or ReferenceLoopHandling.Serialize. System.Text.Json added reference handling support via JsonSerializerOptions.ReferenceHandler, but the API surface is different and migration isn’t always trivial.
// System.Text.Json - handle circular references
var options = new JsonSerializerOptions
{
ReferenceHandler = System.Text.Json.Serialization.ReferenceHandler.Preserve,
WriteIndented = true
};
string json = JsonSerializer.Serialize(myObjectWithCycles, options);
// Newtonsoft.Json - handle reference loops
var settings = new JsonSerializerSettings
{
ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
Formatting = Formatting.Indented
};
string jsonNewton = JsonConvert.SerializeObject(myObjectWithCycles, settings);
2. Dynamic and Anonymous Types
Newtonsoft.Json handles dynamic and JObject/JArray with natural ease. System.Text.Json uses JsonElement and JsonDocument for DOM-style access, which is more verbose but more allocation-friendly. If your codebase heavily uses dynamic deserialization or ExpandoObject, migrating to System.Text.Json can require significant refactoring.
3. Custom Converters and Contract Resolvers
Newtonsoft’s IContractResolver and JsonConverter ecosystem is vast and mature. System.Text.Json introduced JsonConverter<T> and, from .NET 7 onwards, IJsonTypeInfoResolver for advanced customization. However, if you’re relying on community converters built for Newtonsoft.Json, you’ll need to find or write equivalents. This is one of the main blockers for enterprise migrations from large codebases.
System.Text.Json Advanced Features in .NET 8 and .NET 9
Microsoft has been closing the gap rapidly. Here are notable improvements that make System.Text.Json even more compelling in 2026:
Source Generation for Zero-Overhead Serialization
Source generation eliminates reflection at runtime, making System.Text.Json a perfect fit for Native AOT and trimmed deployments. This is something Newtonsoft.Json fundamentally cannot offer due to its reliance on reflection.
using System.Text.Json;
using System.Text.Json.Serialization;
[JsonSourceGenerationOptions(WriteIndented = true)]
[JsonSerializable(typeof(Product))]
[JsonSerializable(typeof(List<Product>))]
public partial class ProductJsonContext : JsonSerializerContext { }
// Usage - no reflection at runtime
string json = JsonSerializer.Serialize(product, ProductJsonContext.Default.Product);
Product? result = JsonSerializer.Deserialize(json, ProductJsonContext.Default.Product);
This approach is particularly powerful when combined with our guide on improving ASP.NET Core web application performance, as it removes serialization overhead from the hot path entirely.
Required Properties and Polymorphism (.NET 7+)
System.Text.Json now supports required properties via the [JsonRequired] attribute and polymorphic serialization via [JsonDerivedType], features that were previously only available in Newtonsoft.Json through workarounds.
using System.Text.Json.Serialization;
[JsonDerivedType(typeof(Dog), typeDiscriminator: "dog")]
[JsonDerivedType(typeof(Cat), typeDiscriminator: "cat")]
public abstract class Animal
{
public string Name { get; set; } = string.Empty;
}
public class Dog : Animal { public string Breed { get; set; } = string.Empty; }
public class Cat : Animal { public bool IsIndoor { get; set; } }
// Polymorphic round-trip
Animal[] animals = [new Dog { Name = "Rex", Breed = "Labrador" }, new Cat { Name = "Whiskers", IsIndoor = true }];
string json = JsonSerializer.Serialize(animals);
Animal[]? deserialized = JsonSerializer.Deserialize<Animal[]>(json);
Practical Migration: Moving from Newtonsoft.Json to System.Text.Json
Migration is often the toughest part. If you’re working on migrating from ASP.NET Framework to ASP.NET Core, you’ll encounter this decision directly. Here’s a common pattern comparison:
// --- Newtonsoft.Json patterns and their System.Text.Json equivalents ---
// 1. Ignore null values
// Newtonsoft:
var settings = new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore };
// System.Text.Json:
var options = new JsonSerializerOptions { DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull };
// 2. Camel case property names
// Newtonsoft:
settings.ContractResolver = new CamelCasePropertyNamesContractResolver();
// System.Text.Json:
options.PropertyNamingPolicy = JsonNamingPolicy.CamelCase;
// 3. Custom date format
// Newtonsoft:
settings.DateFormatString = "yyyy-MM-dd";
// System.Text.Json: requires a custom JsonConverter<DateTime>
// 4. Enum as string
// Newtonsoft:
settings.Converters.Add(new StringEnumConverter());
// System.Text.Json:
options.Converters.Add(new JsonStringEnumConverter());
Note that date format customization in System.Text.Json still requires a custom converter, which is one of the remaining rough edges. The official Microsoft migration guide covers the full list of behavioral differences — it’s worth reading before starting a migration on a large codebase.
Security Considerations
From a security standpoint, System.Text.Json is more strict by default. It doesn’t support TypeNameHandling, which in Newtonsoft.Json was a known vector for deserialization attacks when set to non-None values. This makes System.Text.Json inherently safer out of the box for applications that handle untrusted JSON input.
If you’re building applications with strict security requirements, this is a compelling reason to prefer System.Text.Json — and it aligns with the broader guidance in our post on best practices for securing .NET applications.
Testing JSON Serialization Behavior
Regardless of which library you choose, it’s important to test serialization contracts in your application — especially when upgrading library versions or switching between the two. As covered in our guide on unit testing in .NET: best practices and tools, writing dedicated serialization tests prevents subtle bugs from reaching production.
using System.Text.Json;
using Xunit;
public class ProductSerializationTests
{
[Fact]
public void Serialize_Product_ProducesExpectedJson()
{
var product = new Product { Id = 1, Name = "Widget", Price = 9.99m, CreatedAt = new DateTime(2026, 1, 1, 0, 0, 0, DateTimeKind.Utc) };
var options = new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase };
string json = JsonSerializer.Serialize(product, options);
Assert.Contains("\"id\":1", json);
Assert.Contains("\"name\":\"Widget\"", json);
Assert.Contains("\"price\":9.99", json);
}
[Fact]
public void Deserialize_Json_ReturnsCorrectProduct()
{
string json = "{\"id\":2,\"name\":\"Gadget\",\"price\":19.99,\"createdAt\":\"2026-01-01T00:00:00Z\"}";
var options = new JsonSerializerOptions { PropertyNameCaseInsensitive = true };
Product? result = JsonSerializer.Deserialize<Product>(json, options);
Assert.NotNull(result);
Assert.Equal(2, result.Id);
Assert.Equal("Gadget", result.Name);
}
}
When to Still Use Newtonsoft.Json in 2026
Despite System.Text.Json’s rapid advancement, there are legitimate reasons to keep Newtonsoft.Json:
Legacy codebases: If you have a large codebase with deep Newtonsoft.Json integration (custom resolvers, converters, JObject usage everywhere), migrating is a significant engineering effort with real risk. Stability may outweigh the performance gains.
Complex dynamic JSON: Applications that parse highly dynamic or schema-less JSON where you need LINQ-to-JSON (JToken, JArray) still benefit from Newtonsoft’s ergonomics, though System.Text.Json’s JsonNode API (added in .NET 6) has become a solid alternative.
Third-party library compatibility: Some older third-party libraries explicitly depend on Newtonsoft.Json types. In those cases, you often can’t avoid it without forking or replacing the dependency.
Specific serialization edge cases: Features like preserving property order from a source object, extremely flexible polymorphic hierarchies without known discriminators, or deep JToken manipulation may still be easier with Newtonsoft.
Quick Decision Guide
Use System.Text.Json if: you’re building a new project on .NET 6+, performance and allocation matter, you’re targeting Native AOT, or you want fewer dependencies and built-in ASP.NET Core integration.
Stick with Newtonsoft.Json if: you have a large existing codebase that would require extensive migration, you rely on advanced dynamic JSON features, or a third-party dependency forces the choice.
For greenfield .NET applications developed by a professional .NET development team, System.Text.Json is the default recommendation today. It’s faster, more memory-efficient, natively integrated, and actively invested in by Microsoft.
Conclusion
The System.Text.Json vs Newtonsoft.Json debate in 2026 has a clear lean: System.Text.Json wins for new development. Microsoft has addressed most of the gaps — polymorphism, required properties, reference handling, source generation — making it a production-ready choice for the vast majority of use cases. Newtonsoft.Json remains relevant for legacy migrations and niche scenarios, but its days as the default choice are behind it.
The key takeaway is that this isn’t an all-or-nothing decision. Both libraries can coexist in the same solution if needed, and the migration path is well-documented. Evaluate your specific requirements, test your serialization contracts thoroughly, and make the switch to System.Text.Json when the time is right for your project.
WireFuture stands for precision in every line of code. Whether you're a startup or an established enterprise, our bespoke software solutions are tailored to fit your exact requirements.
No commitment required. Whether you’re a charity, business, start-up or you just have an idea – we’re happy to talk through your project.
Embrace a worry-free experience as we proactively update, secure, and optimize your software, enabling you to focus on what matters most – driving innovation and achieving your business goals.

