.NET 11 Preview 4: The Runtime Just Got a Brain Upgrade
by DeeDee Walsh, on May 17, 2026 1:00:00 AM
.Preview 4 is where the rubber meets the road for .NET 11. We’ve officially moved past the experimental phase and into the things getting real territory. The underlying machinery of your web services and Blazor front ends just got leaner, faster, and much easier to debug. Here's why Preview 4 is the big signal that your 2026 modernization roadmap needs to start thinking about .NET 11.

What's new in Preview 4
Preview 4 has fewer headline features, more rough edges get sanded down, and a couple of meaningful turns of the screw on runtime async. The major ASP.NET Core and runtime changes:
Runtime Async is now compiled into the shared framework libraries
The single biggest signal in Preview 4 is that the shared framework libraries themselves are now built with runtime-async on (dotnet/aspnetcore#66200). In Previews 1–3, Runtime Async was a feature you could opt into for your own code. Now the BCL and ASP.NET Core stack are themselves compiled with it.
Why this matters: every async hop through Kestrel, the pipeline, the HTTP client, EF Core, and your own code is now subject to the runtime's native async machinery rather than the compiler-generated state machine. That's the change Microsoft has been building toward since Preview 1, and the call from the team is explicit. Test your apps against Preview 4 and report regressions, because shared-framework rollout is where surprises surface.
For modernization workloads this is good news. A modernized PowerBuilder DataWindow or VB6 form-handler tends to be aggressively chatty over async I/O once it lands in ASP.NET Core; the cleaner stack traces and lower allocation pressure show up across the whole pipeline rather than just in the leaf method you wrote.
HTTP QUERY method support in OpenAPI 3.2
The IETF's HTTP QUERY method: QUERY as a verb that's like GET but with a request body is now a known method in ASP.NET Core's OpenAPI generation (dotnet/aspnetcore#65714, community contribution from @kilifu). If you set OpenApiVersion = 3.2, the generated document emits an inline query Path Item field. For backward compatibility with OpenAPI 3.0 and 3.1 consumers, the generator emits an x-oai-additionalOperations extension instead.
This is small but useful. Modernized search and reporting endpoints, exactly the things VELO customers most often need to expose from a converted Clarion or Access app, frequently exceed reasonable URL length limits for query parameters. QUERY lets you send the filter shape as a body without losing semantic clarity, and now the OpenAPI tooling can describe it.
TLS handshake observability
Two related additions:
- A new
UseTlsClientHelloListenerextension method that lets you inspect the raw ClientHello before TLS negotiation completes, useful for diagnosing handshake failures with picky client SDKs. - An
ITlsHandshakeFeature.Exceptionproperty surfaced via connection middleware so you can log the actual reason a handshake bailed.
If you've ever spent an afternoon trying to figure out why an HL7 integration partner or a legacy device on a manufacturing floor refuses to talk to your modernized API, this is the diagnostic surface you've been wanting.
Endpoint filters observe binding failures
A long-standing wart: endpoint filters in minimal APIs ran after parameter binding, so if binding produced a 400 Bad Request, your filter never saw it. Preview 4 fixes this (dotnet/aspnetcore#64539). Set RouteHandlerOptions.ThrowOnBadRequest = false (the default outside Development) and your filter now observes the failed bind and can decide how to respond. Log it, transform the response shape, or short-circuit to a different error envelope. The fix is also being backported to .NET 10.0.8.
OpenAPI binary file responses
.Produces<FileContentHttpResult>() now contributes the correct binary schema to the generated OpenAPI document (dotnet/aspnetcore#64562). The annotation is required. The generator emits the schema from your metadata, not by inference. This matters for any modernized app that hands clients a generated PDF, an Excel export, or a downloaded report, which is most of them.
Blazor Virtualize gets serious
Two changes worth calling out:
- Variable heights above the viewport are now handled correctly (
dotnet/aspnetcore#65951). Preview 3 fixed measured-height adaptation for items currently rendered. Preview 4 extends that to items that scroll off the top, so prepend operations no longer cause scroll anchoring to drift. - A new
AnchorModeparameter onVirtualize(dotnet/aspnetcore#66521):Beginning(default, for news-feed / notification UI where you want to hold the top in place when new items arrive) andEnd(for chat or log auto-scroll where you want to stay pinned to the latest entry). It's a[Flags]enum so the two can be combined. For reference-type items, you'll want to provide anItemComparerso the anchoring logic can recognize the same item across renders.
If you're rebuilding a legacy data-entry grid as a Blazor page, this is the difference between a virtualized list that looks right in demos and one that survives real users prepending records, expanding row details, and scrolling fast.
Blazor Web Worker template polish
The Web Worker template introduced in Preview 2 has been renamed, gained InvokeVoidAsync support for fire-and-forget calls, and now ships cancellation/timeout primitives. There's also a fix (dotnet/aspnetcore#65885) for the template failing in published WASM apps because workers weren't inheriting the page's import map.
Blazor Server circuit pause/resume
Preview 4 documents the supported pattern for tracking and pausing active Blazor Server circuits via CircuitHandler.OnConnectionUpAsync and the new onPauseRequested option on Blazor.start(). Useful for graceful drain during deployments; exactly the kind of operational concern that doesn't come up until you're running modernized apps in production at real scale.
One pulled-from-the-notes item to watch: Blazor Gateway
The Preview 4 release notes briefly included a Blazor Gateway section (a Microsoft.AspNetCore.Components.Gateway package that lets standalone Blazor WASM apps proxy backend API calls through YARP without standing up a separate BFF). The section was pulled at the last minute because the package isn't being produced on the build feeds. The fix is in flight (dotnet/aspnetcore#66579) and the content will come back in Preview 5 or a Preview 4 servicing build. Worth tracking if you've been building WASM apps with the DevServer-plus-separate-API pattern.
The .NET 11 picture so far
Step back from Preview 4 and the cumulative .NET 11 story has four big themes.
1. Async gets pushed into the runtime
Runtime Async is the headline change of the release. The C# compiler has rewritten every async method into a state machine since C# 5, with the well-known cost: noisy stack traces (call stacks become nonsense past the first await), elevated allocations, and reduced ahead-of-time-compilation friendliness. .NET 11 moves that machinery into the runtime itself. Preview 1 introduced it as an opt-in CoreCLR feature; Preview 3 added NativeAOT and ReadyToRun support and dropped the EnablePreviewFeatures=true requirement; Preview 4, as covered above, turns it on for the shared framework libraries.
For modernized apps, the operational payoff is in three places: profilers and APM tools see real method frames instead of state-machine plumbing, GC pressure drops in high-concurrency request paths, and Native AOT becomes viable for a much wider set of services.
2. WebAssembly converges on CoreCLR
For years, Blazor WebAssembly has run on Mono while everything server-side has run on CoreCLR. .NET 11 begins the multi-year migration to one runtime everywhere by bringing up a WASM-targeting RyuJIT. Preview 1 laid the foundation; Preview 3 added WebCIL payload loading and better debugging symbols, plus more direct marshaling for float[], Span<float>, and ArraySegment<float> across the JS boundary.
This isn't done in .NET 11, but the trajectory is clear: server and browser .NET will share one execution engine, with the JIT optimizations and GC tuning that have been making server-side .NET fast for a decade finally available to your Blazor WASM front end.
3. Compression, AI primitives, and language ergonomics in the libraries
The Base Class Library work across Previews 1–3 is the most production-relevant bucket for line-of-business modernization work:
- Zstandard compression is now native (
System.IO.Compression.ZstandardStream), with full streaming, one-shot, and dictionary-based APIs. ASP.NET Core middleware enables zstd response compression and request decompression by default. Zstd is typically 2–7× faster compressing and up to 14× faster decompressing than gzip at comparable ratios which is meaningful in any data-heavy pipeline. - BFloat16 lands as a first-class floating-point type for AI/ML workloads.
BitConverterknows about it. - System.Text.Json gains per-member naming policy overrides, a new
JsonNamingPolicy.PascalCase, and type-level ignore conditions. - EF Core 11 adds vector search support for SQL Server,
MaxBy/MinBytranslation, aGetEntriesForStateAPI onChangeTrackerthat doesn't force aDetectChangespass, and JSON mapping for complex types in inheritance hierarchies (excluding TPH). - C# 15 introduces collection expression arguments (
[with(capacity: 100), .. values]) and, in Preview 2, union types, a long-requested by the community, with full IDE integration arriving in Preview 3.
4. SDK and tooling get sharper
The CLI work isn't flashy but adds up:
dotnet runis now interactive when you don't specify a TFM or device, significant for MAUI and mobile development.dotnet run -e KEY=valuefor inline environment variables.- File-based app support via
#:includefor splitting a script across files. dotnet slncan create and edit solution filter files (.slnf).dotnet watchintegrates with Aspire app hosts, recovers from crashes, hot-reloads project and package reference changes, and handles Ctrl+C cleanly for WinForms/WPF.- Container images shrink by up to 17% via hard links.
What this means for modernization teams
If you're planning a modernization roadmap, three implications:
Target .NET 11 when modernizing, not .NET 10. This sounds counterintuitive: .NET 10 is the LTS but the runtime async work, the WebAssembly convergence, and the cleaner Blazor primitives in .NET 11 are exactly what a newly modernized application benefits from most. Apps that have been on .NET 10 since November and are running fine in production are the ones that should stay on the LTS. Apps you're moving off legacy stacks this year start clean: there's no upgrade tax, and you get a year of STS support to settle in before the next LTS arrives.
Plan a runtime-async regression pass. Because Preview 4 turns runtime-async on for the shared framework, behavior changes in third-party libraries and your own deep-async code paths are the most likely sources of surprise. Build it into your acceptance criteria for any preview-targeted pilot.
Re-evaluate WASM target decisions. Teams who chose Blazor Server because of WASM startup or performance concerns should plan to revisit that decision in 2027 once CoreCLR-on-WASM is closer to general availability. The architectural picture is going to look different.
Where to go from here
- Preview 4 SDK download: dotnet.microsoft.com/download/dotnet/11.0
- Microsoft Learn — What's new in .NET 11
- Release notes (canonical): dotnet/core on GitHub, release-notes/11.0/preview/preview4
- .NET 11 GA target: November 2026 at .NET Conf
The cadence from here is one preview per month through summer, then release candidates in September and October. For teams sequencing modernization releases, that gives a reasonable window to pilot Preview 5 or 6 against a representative workload and have a real opinion on the GA shape by the end of Q3.



