.NET 11 Preview 3: Union Types, Runtime Async and Notable Improvements
Posted on: 4/25/2026 5:16:37 AM
Table of contents
- 1. C# Union Types — The Most Anticipated Feature
- 2. Runtime Async — From Preview to Stable
- 3. Zstandard Compression — Faster and Smaller
- 4. JIT Compiler — Deep Performance Optimizations
- 5. System.Text.Json — More Control
- 6. Entity Framework Core 11 — Smarter Queries
- 7. HTTP/3 in ASP.NET Core — Earlier Processing
- 8. SafeFileHandle & RandomAccess — Expanded Pipe Support
- 9. Regex — Unicode Newline Support
- 10. Container Images — Cryptographic Signing
- 11. SDK — Developer Experience Improvements
- 12. .NET 11 Roadmap
- 13. Should You Upgrade to .NET 11 Preview?
- References
Microsoft released .NET 11 Preview 3 on April 14, 2026, packed with significant improvements across the C# language, runtime, ASP.NET Core, and Entity Framework Core. This is the third preview on the road to GA in November 2026, and it brings the most anticipated feature: Union Types.
1. C# Union Types — The Most Anticipated Feature
Union Types is the biggest language feature in .NET 11 Preview 3. If you've worked with TypeScript, F#, or Rust, this will feel familiar — it lets you declare a variable that can be one of several specific types, verified at compile-time.
1.1. The Problem Union Types Solve
Before .NET 11, when a method could return different result types, you had to:
- Use
objectand cast — losing type safety - Create abstract class/interface hierarchies — lots of boilerplate
- Use
OneOf<T1,T2>from NuGet — not a first-class citizen - Use
Result<T>patterns — convention-based, not compiler-enforced
// BEFORE .NET 11: Class hierarchy approach
public abstract record PaymentResult;
public record PaymentSuccess(string TransactionId) : PaymentResult;
public record PaymentFailed(string Error) : PaymentResult;
public record PaymentPending(DateTime RetryAfter) : PaymentResult;
// Manual type checking required
if (result is PaymentSuccess success) { ... }
else if (result is PaymentFailed failed) { ... }
// Compiler does NOT warn if you forget to handle PaymentPending!
// .NET 11: Union Types
union PaymentResult = PaymentSuccess | PaymentFailed | PaymentPending;
public record PaymentSuccess(string TransactionId);
public record PaymentFailed(string Error);
public record PaymentPending(DateTime RetryAfter);
// EXHAUSTIVE pattern matching — compiler forces you to handle all cases
string message = result switch
{
PaymentSuccess s => $"Paid: {s.TransactionId}",
PaymentFailed f => $"Error: {f.Error}",
PaymentPending p => $"Retry at: {p.RetryAfter}",
// No default needed — compiler knows all cases are covered!
};
Exhaustive Pattern Matching
The greatest strength of Union Types is that the compiler forces you to handle every case. If you later add a new variant (e.g., PaymentRefunded), every unhandled switch expression will produce a compile-time error — no more hidden runtime bugs.
1.2. Practical Applications
// Cleaner API error handling
union ApiResponse<T> = Success<T> | ValidationError | NotFound | Unauthorized;
public async Task<ApiResponse<Order>> GetOrder(int id)
{
if (!IsAuthenticated) return new Unauthorized();
var order = await _db.Orders.FindAsync(id);
if (order is null) return new NotFound();
return new Success<Order>(order);
}
// Controller handling
var response = await _service.GetOrder(id);
return response switch
{
Success<Order> s => Ok(s.Value),
ValidationError v => BadRequest(v.Errors),
NotFound => NotFound(),
Unauthorized => Unauthorized(),
};
2. Runtime Async — From Preview to Stable
One of the most important runtime changes: Runtime Async has removed the preview API opt-in requirement. This means async/await is now handled directly by the runtime instead of compiler-generated state machines.
graph LR
A["async/await Code"] --> B{"Runtime Async
.NET 11"}
B --> C["JIT handles directly
No state machine"]
B --> D["Fewer allocations
Less GC pressure"]
A --> E{"Old approach
.NET 10"}
E --> F["Compiler generates
State Machine class"]
E --> G["More allocations
Task objects"]
style B fill:#4CAF50,stroke:#fff,color:#fff
style E fill:#e94560,stroke:#fff,color:#fff
style C fill:#f8f9fa,stroke:#4CAF50,color:#2c3e50
style D fill:#f8f9fa,stroke:#4CAF50,color:#2c3e50
style F fill:#f8f9fa,stroke:#e94560,color:#2c3e50
style G fill:#f8f9fa,stroke:#e94560,color:#2c3e50
Figure 1: Async handling comparison between .NET 10 and .NET 11
Practical benefits:
- Reduced memory allocation: No more state machine classes generated for each async method
- Less GC pressure: Fewer short-lived objects to collect
- Cleaner stack traces: Debugging async code is easier without MoveNext() clutter
- Zero code changes required: Just target .NET 11 and performance improves automatically
3. Zstandard Compression — Faster and Smaller
Zstandard (zstd) — the compression algorithm developed by Facebook — officially joins System.IO.Compression in .NET 11. Previously, you needed third-party NuGet packages.
| Algorithm | Compression Ratio | Compression Speed | Decompression Speed | Best For |
|---|---|---|---|---|
| Zstandard | High | Very fast | Extremely fast | API responses, real-time data |
| Brotli | Very high | Slow | Fast | Static assets, CDN |
| Gzip | Medium | Medium | Fast | Backward compatibility |
| Deflate | Low | Fast | Fast | Legacy, ZIP files |
3.1. ASP.NET Core Response Compression
// ASP.NET Core natively supports Zstandard response compression
builder.Services.AddResponseCompression(options =>
{
options.EnableForHttps = true;
options.Providers.Add<ZstandardCompressionProvider>();
options.Providers.Add<BrotliCompressionProvider>();
options.Providers.Add<GzipCompressionProvider>();
});
// Automatic request decompression is also supported
builder.Services.AddRequestDecompression();
4. JIT Compiler — Deep Performance Optimizations
The JIT compiler in .NET 11 Preview 3 improves three key areas:
4.1. Switch Statement Optimization
JIT now generates more efficient jump tables for switch statements, especially for pattern matching with Union Types — a perfect complement to the new language feature.
4.2. Bounds Check Elimination
// JIT automatically removes bounds checks when it can prove safety
Span<int> data = stackalloc int[100];
for (int i = 0; i < data.Length; i++)
{
data[i] = i * 2; // No bounds check needed — JIT knows i < Length
}
4.3. Cast Optimization
Type checks (is, as, casts) are now faster as JIT reuses type check results within the same method, avoiding redundant method table lookups.
5. System.Text.Json — More Control
// More granular control over JSON serialization
var options = new JsonSerializerOptions
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
// NEW: Control ignore behavior for default values
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingDefault
};
// Union Types work seamlessly with JSON serialization
union Shape = Circle | Rectangle | Triangle;
// Automatic serialize/deserialize with type discriminator
string json = JsonSerializer.Serialize<Shape>(new Circle(5.0));
// {"$type":"Circle","radius":5.0}
6. Entity Framework Core 11 — Smarter Queries
6.1. ChangeTracker.GetEntriesForState()
// BEFORE: Triggers full change detection
var modified = context.ChangeTracker.Entries()
.Where(e => e.State == EntityState.Modified);
// .NET 11: Only retrieves entries at specific state, no full scan
var modified = context.ChangeTracker
.GetEntriesForState(EntityState.Modified);
6.2. Redundant JOIN Elimination
EF Core 11 is smarter at detecting and removing unnecessary JOINs in generated SQL. For complex queries, this can significantly reduce execution time.
6.3. SQL Server JSON APIs
// Query JSON columns directly from LINQ
var orders = await context.Orders
.Where(o => EF.Functions.JsonContains(
o.Metadata, """{"priority": "high"}"""))
.ToListAsync();
7. HTTP/3 in ASP.NET Core — Earlier Processing
ASP.NET Core 11 improves HTTP/3 by starting request processing earlier in the pipeline, reducing time-to-first-byte. Combined with Zstandard compression, this is a significant step forward for Web Performance.
graph TD
A["Client sends request
HTTP/3 + QUIC"] --> B["Kestrel receives stream"]
B --> C{"Earlier processing
.NET 11"}
C --> D["Parse headers
immediately on receipt"]
D --> E["Start middleware
pipeline"]
E --> F["Response + Zstd
compression"]
style C fill:#e94560,stroke:#fff,color:#fff
style F fill:#4CAF50,stroke:#fff,color:#fff
Figure 2: Improved HTTP/3 pipeline in .NET 11
8. SafeFileHandle & RandomAccess — Expanded Pipe Support
SafeFileHandle and RandomAccess now support pipes (named and anonymous), allowing the same API for both file I/O and inter-process communication:
// Using RandomAccess API with pipes — new in .NET 11
using var pipe = new NamedPipeServerStream("myPipe");
await pipe.WaitForConnectionAsync();
var handle = pipe.SafePipeHandle;
// Now you can use RandomAccess patterns for pipe I/O
byte[] buffer = new byte[1024];
int bytesRead = await RandomAccess.ReadAsync(
handle, buffer, fileOffset: 0);
9. Regex — Unicode Newline Support
The Regex engine in .NET 11 recognizes all Unicode newline sequences, not just \r\n and \n:
\n— Line Feed (U+000A)\r\n— Carriage Return + Line Feed\r— Carriage Return (U+000D)\u0085— Next Line (NEL)\u2028— Line Separator\u2029— Paragraph Separator
Potential Breaking Change
If your regex uses . (dot) with RegexOptions.Multiline, behavior may change as dot now excludes additional Unicode newlines. Review your regex patterns if processing text from international sources.
10. Container Images — Cryptographic Signing
.NET 11 container images are now cryptographically signed, allowing you to verify image integrity before deployment. This is an important step for supply chain security in CI/CD pipelines.
# Verify .NET 11 container image signature
cosign verify mcr.microsoft.com/dotnet/aspnet:11.0-preview.3 \
--certificate-identity-regexp ".*microsoft.*" \
--certificate-oidc-issuer "https://token.actions.githubusercontent.com"
11. SDK — Developer Experience Improvements
| Feature | Description | Benefit |
|---|---|---|
| Solution Filters CLI | Edit solution filters from command line | Automate CI/CD without opening VS |
| Multi-file entry points | Split file-based apps across multiple files | More complex script-style apps stay clean |
| dotnet run -e | Pass environment variables from CLI | No need for .env or launchSettings.json |
| dotnet watch + Aspire | Hot reload supports Aspire apps | Faster dev loop for distributed apps |
12. .NET 11 Roadmap
STS vs LTS
.NET 11 is an STS release (Standard Term Support — 18 months). If you need LTS (3 years), stay on .NET 10. However, if you want to experience Union Types and Runtime Async now, .NET 11 is worth considering for new projects.
13. Should You Upgrade to .NET 11 Preview?
- Side projects & experiments: Absolutely — especially to learn Union Types
- Greenfield projects: Consider it if your timeline allows waiting for GA (11/2026)
- Production apps: Wait for at least RC1, preferably GA + 1-2 servicing updates
- Libraries/NuGet packages: Start testing compatibility early, but don't release targeting .NET 11 yet
References
API Versioning — Production-Ready Strategies for Managing API Versions
GraphQL Federation — Building a Unified API Gateway for Microservices
Disclaimer: The opinions expressed in this blog are solely my own and do not reflect the views or opinions of my employer or any affiliated organizations. The content provided is for informational and educational purposes only and should not be taken as professional advice. While I strive to provide accurate and up-to-date information, I make no warranties or guarantees about the completeness, reliability, or accuracy of the content. Readers are encouraged to verify the information and seek independent advice as needed. I disclaim any liability for decisions or actions taken based on the content of this blog.