TL;DR:.NET 11 Preview 1 brings Zstandard compression, AI/ML types, async runtime upgrades, and UI/tooling improvements. Preview 2 extends this with Blazor TempData, OpenTelemetry, EF Core vector search, smaller SDK images, MAUI enhancements, and further performance gains.
.NET 11 Preview 1 and Preview 2 are out, and they’re worth a look if you build high-throughput services, modern web apps with Blazor, or you’re starting to bring AI-ish workloads (embeddings, semantic search, model inference) into “normal” line-of-business systems.
This post focuses on four updates that materially change what you can do (or how easy it is to do it):
- Runtime Async (Preview 1, refined in Preview 2).
- Native Zstandard (zstd) compression (Preview 1).
- Blazor TempData for SSR (Preview 2).
- EF Core vector search for SQL Server (Preview 2).
I’ll also call out a few smaller but meaningful tooling/platform changes at the end.
What shipped in Preview 1 vs Preview 2 (quick map)
Preview 1 highlights
- Native Zstandard (zstd) compression APIs.
- Runtime Async foundation (enabled for experimentation via preview features).
-
BFloat16type for AI/ML and numerics scenarios. - C# preview improvements like collection expression arguments.
Preview 2 highlights
- Blazor TempData support for static SSR scenarios.
- Native OpenTelemetry tracing support in ASP.NET Core (baseline enablement).
- EF Core vector search support for SQL Server (vector distance + indexing support).
- Runtime Async V2 refinements.
- Smaller SDK/container images and a bunch of runtime/SDK polish.
Libraries: Powerful new APIs and performance wins
The Base Class Library (BCL) gains several production-ready additions that solve real-world pain points.
Zstandard compression support
Need to shrink files or speed up data transfer? .NET now natively supports Zstandard (zstd), a modern algorithm that’s often faster than GZip or Brotli while keeping excellent compression ratios.
In web servers, logging pipelines, or big-data scenarios, Zstandard delivers 2–7x faster compression and up to 14x faster decompression (per official benchmarks). Lower latency and storage costs in production.
Example implementation:
using System.IO.Compression;
// Compress data
{
using var inputStream = File.OpenRead("largefile.txt");
using var outputStream = File.Create("compressed.zst");
using var compressStream = new ZstandardStream(outputStream, CompressionMode.Compress);
await inputStream.CopyToAsync(compressStream);
}
// Decompress
{
using var decompressInput = File.OpenRead("compressed.zst");
using var decompressOutput = File.Create("restored.txt");
using var decompressStream = new ZstandardStream(decompressInput, CompressionMode.Decompress);
await decompressStream.CopyToAsync(decompressOutput);
}

Pro tip: Pair it with HttpClientHandler.AutomaticDecompression for automatic zstd handling in APIs that helps you transmit significantly less data during HTTP data transfers if the payload is compressible.
Here’s the code example in C#:
var handler = new HttpClientHandler
{
AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Zstandard
};
using var client = new HttpClient(handler);
// Automatically decompresses zstd-encoded responses
var response = await client.GetAsync("https://example.com");
BFloat16 floating-point type
Machine-learning models need numbers that balance range and memory. BFloat16 (16-bit “Brain Float”) gives you the wide range of a regular float while using half the memory.
Ideal for tensor operations in ML.NET, ONNX Runtime, or custom AI pipelines. Reduced memory footprint = larger models or batches on the same hardware.
Here’s the example C# code:
BFloat16 value = (BFloat16)3.14f;
float regularFloat = (float)value; // Lossless upcast to float
// ML-style computation
BFloat16 a = (BFloat16)1.5f;
BFloat16 b = (BFloat16)2.0f;
BFloat16 result = a * b; // 3.0
C# collection expression arguments
Collection expressions ([]) just got smarter. You can now pass constructor arguments like capacity or a custom comparer directly inside the brackets. Pre-allocate capacity to avoid reallocations on hot paths; use an immutable FrozenDictionary or case-insensitive set with zero extra code.
Example implementation:
string[] values = ["apple", "banana", "cherry"];
// Set initial capacity as twice the capacity for better performance
List<string> names = [with(capacity: values.Length * 2), .. values];
Case-insensitive HashSet
HashSet<string> uniqueNames =
[
with(StringComparer.OrdinalIgnoreCase),
"Apple",
"apple",
"BANANA"
];
foreach (var name in uniqueNames)
{
Console.WriteLine(name);
// Outputs "Apple" and "BANANA" only once each
}
Note: To enable preview features, you need to set the LangVersion property to preview in your project.
<PropertyGroup>
<LangVersion>preview</LangVersion>
</PropertyGroup>
Beyond collection expression arguments, extended layout support improves interop scenarios (great for performance-critical libraries). The language team continues making C# more concise and expressive, exactly what both new and veteran developers love.
Entity Framework Core improvements
Entity Framework Core continues to evolve in .NET 11 Preview 1 & 2 with several developer-friendly enhancements that make data access more expressive and productive.
The most notable addition is full support for complex types and JSON columns on entity types that use TPT (Table-Per-Type) or TPC (Table-Per-Concrete-Type) inheritance mappings. A long-requested capability that lets beginners model real-world hierarchical business objects (like an Animal base class with nested Details stored as JSON) without workarounds, while experienced architects gain powerful flexibility for rich domain-driven designs:
Here’s the code example in C#:
using Microsoft.EntityFrameworkCore;
using System.ComponentModel.DataAnnotations.Schema;
Main(args).GetAwaiter().GetResult();
public abstract class Animal
{
public int Id { get; set; }
public string Name { get; set; } = string.Empty;
public required AnimalDetails Details { get; set; }
}
public class Dog : Animal
{
public string? Breed { get; set; }
}
public class Cat : Animal
{
public bool IsIndoor { get; set; }
}
[ComplexType]
public class AnimalDetails
{
public DateTime BirthDate { get; set; }
public string? Veterinarian { get; set; }
}
public class ApplicationDbContext : DbContext
{
public DbSet<Animal> Animals { get; set; }
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : base(options) { }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
// New in .NET 11 / EF Core 11:
// Complex types can now be stored as JSON columns with TPT/TPC inheritance
modelBuilder.Entity<Animal>()
.UseTptMappingStrategy()
.ComplexProperty(a => a.Details, b => b.ToJson());
modelBuilder.Entity<Dog>();
modelBuilder.Entity<Cat>();
}
}
partial class Program
{
static async Task Main(string[] args)
{
var connectionString = "Data Source=SYNCLAPN-44605;Initial Catalog=AnimalDbTest;Integrated Security=True;Encrypt=False";
var options = new DbContextOptionsBuilder<ApplicationDbContext>()
.UseSqlServer(connectionString)
.Options;
await using var context = new ApplicationDbContext(options);
// Create database + tables (perfect for quick testing)
await context.Database.EnsureCreatedAsync();
Console.WriteLine("Database created successfully!\n");
// === INSERT TEST DATA ===
var dog = new Dog
{
Name = "Buddy",
Breed = "Labrador",
Details = new AnimalDetails
{
BirthDate = new DateTime(2022, 5, 15),
Veterinarian = "Dr. Smith"
}
};
var cat = new Cat
{
Name = "Luna",
IsIndoor = true,
Details = new AnimalDetails
{
BirthDate = new DateTime(2023, 1, 10),
Veterinarian = "Dr. John"
}
};
context.Animals.AddRange(dog, cat);
await context.SaveChangesAsync();
Console.WriteLine("Inserted Dog and Cat successfully!\n");
// === QUERY & DISPLAY ===
Console.WriteLine("Dogs:");
var dogs = await context.Animals.OfType<Dog>().ToListAsync();
foreach (var d in dogs)
{
Console.WriteLine($" • {d.Name} ({d.Breed}) - Born: {d.Details.BirthDate:yyyy-MM-dd}, Vet: {d.Details.Veterinarian}");
}
Console.WriteLine("\nCats:");
var cats = await context.Animals.OfType<Cat>().ToListAsync();
foreach (var c in cats)
{
Console.WriteLine($" • {c.Name} (Indoor: {c.IsIndoor}) - Born: {c.Details.BirthDate:yyyy-MM-dd}, Vet: {c.Details.Veterinarian}");
}
// See the actual JSON stored in the database
Console.WriteLine("\Raw JSON column example (Details column from SQL):");
var raw = await context.Database
.SqlQueryRaw<string>("SELECT Details FROM Animals WHERE Id = 1")
.ToListAsync();
Console.WriteLine(raw.FirstOrDefault() ?? "No data");
}
}
This will create a JSON column (e.g., Details) in the base Animal table while still using separate tables for Dog and Cat (TPT).
This article was originally published at Syncfusion.com.
Top comments (0)