If you've ever wondered why Newtonsoft.Json.dll shows up in your test output directory even though you never referenced it, the answer has been VSTest. The .NET test platform has silently carried Newtonsoft.Json as a transitive dependency for years, leaking it into every test project's bin folder. That era is ending.
Starting with .NET 11 Preview 4 (due May 12, 2026) and Visual Studio 18.8 Insiders 1 (June 9, 2026), VSTest no longer ships Newtonsoft.Json. The platform has migrated its internal serialisation to System.Text.Json on .NET and JSONite on .NET Framework. Most projects won't notice. Some will break at compile time or runtime — and the fix is straightforward once you know what to look for.
Why now?
Three forces are driving this change.
Security exposure. Every version of Newtonsoft.Json below 13.0.1 is flagged as vulnerable on NuGet.org due to CVE-2024-21907, a denial-of-service flaw in JsonConvert.DeserializeObject triggered by deeply nested input. Bundling Newtonsoft.Json in the SDK means Microsoft must monitor and service a component that VSTest no longer needs. Removing it eliminates that surface entirely.
SDK trimming. The .NET SDK historically shipped multiple copies of Newtonsoft.Json.dll across its layout. Issue dotnet/sdk#53287 tracks the broader effort to remove Newtonsoft.Json from the SDK altogether, reducing installation size and simplifying servicing. VSTest was one of the last holdouts.
Native AOT readiness. Newtonsoft.Json relies heavily on runtime reflection, which is fundamentally incompatible with ahead-of-time compilation. System.Text.Json's source generator model fits the AOT story cleanly. While VSTest itself isn't an AOT-compiled binary, removing reflection-heavy dependencies aligns the test platform with the direction of the ecosystem.
How the migration works internally
The VSTest team didn't simply swap one JSON library for another. They implemented a dual-serialiser architecture using conditional compilation:
- On .NET (net10.0+): System.Text.Json handles all serialisation
- On .NET Framework / netstandard2.0: JSONite, a lightweight BSD-2 licensed library by Alexandre Mutel, takes over
The approach avoids runtime branching entirely. The core JsonDataSerializer class is split into three partial classes — shared logic, System.Text.Json-specific code, and JSONite-specific code — with #if NETCOREAPP directives isolating each implementation at compile time.
public partial class JsonDataSerializer
{
public string Serialize<T>(T data) => SerializeCore(data);
public T Deserialize<T>(string json) => DeserializeCore<T>(json);
}
#if NETCOREAPP
public partial class JsonDataSerializer
{
private string SerializeCore<T>(T data)
=> JsonSerializer.Serialize(data, _options);
private T DeserializeCore<T>(string json)
=> JsonSerializer.Deserialize<T>(json, _options);
}
#endif
The team wrote over 12 custom JsonConverter<T> implementations for VSTest types like TestCase, TestResult, and TestProperty, plus a matching set of JSONite converters that handle both V1 and V2 wire formats including private setter access.
One particularly interesting challenge was Message.Payload. Previously typed as Newtonsoft.Json.Linq.JToken, it's now System.Text.Json.JsonElement?. The team also introduced a RawMessage string property for deferred deserialisation — the platform can forward messages between processes without parsing them.
// NOTE
The wire format itself is unchanged. Messages serialise identically regardless of which JSON library produces them. Older test hosts remain compatible with the updated platform, and vice versa.
Will your tests break?
For most projects: no. If your test project doesn't use Newtonsoft.Json types directly, or if it already declares an explicit PackageReference, nothing changes.
Three scenarios do break.
1. Accidental dependency on the leaked assembly
This is the most common issue. Your test project uses JObject, JsonConvert, or other Newtonsoft.Json types, but you never added the package — it compiled because VSTest's copy was sitting in the output directory.
<!-- This worked before because VSTest leaked Newtonsoft.Json -->
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net11.0</TargetFramework>
</PropertyGroup>
<!-- No PackageReference for Newtonsoft.Json — will now fail to compile -->
</Project>
Symptom: Compile error — types from Newtonsoft.Json not found.
Fix: Add the package reference explicitly:
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
2. ExcludeAssets suppressing the runtime copy
Some projects reference Newtonsoft.Json but exclude runtime assets, relying on VSTest to provide the DLL at runtime:
<PackageReference Include="Newtonsoft.Json" Version="13.0.3">
<ExcludeAssets>runtime</ExcludeAssets>
</PackageReference>
Symptom: System.IO.FileNotFoundException: Could not load file or assembly 'Newtonsoft.Json, Version=13.0.0.0'
Fix: Remove the <ExcludeAssets>runtime</ExcludeAssets> line, or remove it and let the package copy its DLL normally.
3. Custom test adapters and data collectors
If you've authored a test adapter or data collector that uses Newtonsoft.Json without declaring it as a dependency, the extension will fail to load. The VSTest team notes they aren't aware of any shipping adapter that hits this today, but internal or bespoke adapters might.
Symptom: System.IO.FileNotFoundException at extension load time.
Fix: Add Newtonsoft.Json as an explicit dependency in your extension package, or migrate to System.Text.Json.
// TIP
You can test against the new behaviour today using the alpha packages. Install Microsoft.TestPlatform.* version 1.0.0-alpha-stj in your test project and run your full suite before the preview drops.
What about xUnit, NUnit, and MSTest?
The major test frameworks are unaffected in practice. xUnit and NUnit on .NET already required explicit Newtonsoft.Json references when tests used it — the leaked dependency was only relevant in specific .NET Framework AppDomain configurations. MSTest similarly doesn't surface Newtonsoft.Json types in its public API.
If you use a test framework that wraps Newtonsoft.Json for assertion serialisation (some assertion libraries do), check whether that library declares its own dependency. If it does, you're fine. If it was piggybacking on VSTest's copy, you'll hit the same FileNotFoundException.
The public API change
VSTest exposed Newtonsoft.Json.Linq.JToken in one spot: the Message.Payload property used in VSTest's communication protocol. This was only meaningful to code participating directly in the VSTest protocol — custom test runners, adapters implementing ITestDiscoveryEventsHandler, or tools communicating over the test platform's JSON wire protocol.
The property type changes from JToken? to JsonElement?. If you have code that directly inspects VSTest protocol messages:
// Bad — no longer compiles
JToken payload = message.Payload;
var testCase = payload.ToObject<TestCase>();
// Good — use the new API
JsonElement? payload = message.Payload;
var testCase = JsonSerializer.Deserialize<TestCase>(
payload.Value.GetRawText());
The VersionedMessage class has also been removed and unified into the single Message type.
Performance
The VSTest team benchmarked the new serialisation against Newtonsoft.Json, and the results favour the migration:
| Operation | System.Text.Json | JSONite |
|---|---|---|
| Serialise 1,000-result StatsChange | ~11 ms | ~36 ms |
| Deserialise 1,000-result StatsChange | ~60 ms | ~96 ms |
These numbers matter less for individual test runs (you won't feel the difference on a 50-test suite) and more for large-scale CI pipelines processing thousands of test results per run. The reduced GC pressure from System.Text.Json is a welcome bonus in memory-constrained build agents.
The broader picture
VSTest's migration is one piece of a larger initiative tracked in dotnet/sdk#53287 to remove Newtonsoft.Json from the .NET SDK entirely. ASP.NET Core has already migrated its JSON Patch implementation to System.Text.Json. The SDK's configuration tooling is following suit.
This doesn't mean Newtonsoft.Json is going away. It remains a well-maintained library with features System.Text.Json still doesn't match — notably JsonPath queries, JToken-based dynamic manipulation, and more permissive deserialisation. But the .NET platform itself is decoupling from it, and that's the right call for a component that ships to every .NET developer on earth.
Common pitfalls
Assuming your tests pass because they compiled. The leaked dependency is a runtime issue in scenario 2 above. Your project builds successfully but tests fail with FileNotFoundException at execution time. Run your test suite, don't just build it.
Pinning to an old Microsoft.NET.Test.SDK. If you freeze the test SDK at a pre-Preview 4 version, you'll continue to carry the Newtonsoft.Json dependency. That delays the problem but doesn't solve it — eventually you'll need to upgrade.
Multi-targeting with shared test projects. If your test project multi-targets net48 and net11.0, the .NET 11 leg will stop providing Newtonsoft.Json while the .NET Framework leg may still get it from other sources. Test both target frameworks explicitly.
Transitive dependency confusion. After adding an explicit PackageReference for Newtonsoft.Json, ensure you're not pulling in conflicting versions through other packages. Use dotnet list package --include-transitive to audit your dependency graph.
Summary
- VSTest drops Newtonsoft.Json starting in .NET 11 Preview 4 (May 12, 2026) and Visual Studio 18.8 (June 9, 2026)
- Internal serialisation now uses System.Text.Json on .NET and JSONite on .NET Framework
- The wire format is unchanged — older and newer test hosts remain compatible
- Most projects need no changes; affected projects need an explicit
PackageReferencefor Newtonsoft.Json - The
Message.Payloadproperty changes fromJToken?toJsonElement?— only relevant if you interact with the VSTest protocol directly - Test your projects against the alpha packages (
1.0.0-alpha-stj) now to catch issues before the preview lands