.NET 11 Preview 3: Union Types, Runtime Async and Notable Improvements

Posted on: 4/25/2026 5:16:37 AM

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.

Union Types Most anticipated C# language feature
Zstandard New compression in System.IO
Runtime Async Graduated from preview to stable
HTTP/3 Earlier request processing, lower latency

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 object and 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

February 2026
Preview 1 — Initial features, basic runtime improvements.
March 2026
Preview 2 — EF Core improvements, SDK enhancements.
April 2026
Preview 3 (current) — Union Types, Runtime Async stable, Zstandard, HTTP/3 improvements.
May-Sep 2026
Preview 4-7 — Continued feature development and stabilization.
October 2026
RC 1 & RC 2 — Release candidates, feature-complete.
November 2026
.NET 11 GA — Official release, STS (Standard Term Support) 18 months.

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