New Features in .NET 10 and C# 14
.NET 10 is out, and if you’ve been waiting for a solid Long-Term Support (LTS) release before upgrading your apps, this is the one. Microsoft will support it until late 2028, providing you with ample time to make the necessary adjustments.
I’ve been testing .NET 10 and C# 14 over the last couple of weeks, and honestly, this release feels like one of the more “balanced” ones. It’s not a dramatic rewrite of anything, but it does bring meaningful improvements to the runtime, the SDK, and especially the C# language.
In this post, I’ll walk you through the updates that actually matter, the ones you will use, the ones that will impact your everyday coding, and a few that made me raise an eyebrow in a good way.
Here’s what we’ll cover:
- What’s new in .NET 10
- What’s new in C# 14
- Whether you should upgrade right now
Let’s get into it.
What’s New in .NET 10
.NET 10 is one of those releases where you don’t notice everything right away, but the moment you start working with it, things just feel smoother. Faster. More polished. Less quirky.
Here are the highlights worth calling out.
1. Performance Improvements (the usual, but still impressive)
Every .NET release comes with the “we made the runtime faster” sentence — and every year, it's true.
In .NET 10, we get:
- Better JIT inlining
- Smarter method devirtualization
- Improved stack allocations
- Optimized code generation for structs
- Enhanced loop inversion
- AVX10.2 support for modern CPUs
If you're building APIs, games, backend systems, cloud functions, or, honestly, anything that runs often and runs hot, you’ll appreciate the gains. The cool part is that you don’t have to do anything. Your existing code benefits automatically.
2. NativeAOT is getting real
NativeAOT started out as a niche feature. Something you’d try for fun, but not something you’d use in a production pipeline.
That’s changed.
.NET 10 brings better:
- Compilation speed
- Reliability
- Output size
- Error messages
- Platform support
The gap between “normal apps” and NativeAOT apps is shrinking, and for some workloads (CLI tools, microservices, Lambdas), AOT is becoming the obvious choice.
I wouldn’t be surprised if AOT becomes the default for some project types in the future.
3. New library APIs across security, JSON, and networking
Some highlights that stood out:
Cryptography
- Expanded post-quantum cryptography
- ML-DSA improvements
- AES KeyWrap with Padding
- Better Windows CNG support
Security people are going to like this one.
JSON Serialization
- Reject duplicate properties
- Stricter JSON settings
- PipeReader support for high-throughput streaming
These changes are beneficial for workloads that rely heavily on APIs.
Networking
- WebSocketStream (makes WebSockets so much nicer to use)
- TLS 1.3 support on macOS
Nothing groundbreaking, but solid improvements.
4. SDK Improvements That Actually Help Developers
There are a few SDK updates that instantly make life easier:
✔ New testing platform support
dotnet test now integrates with Microsoft.Testing.Platform.
More detailed diagnostics. More flexible output. Cleaner experience.
✔ Native shell tab-completion
No more manually wiring up shell scripts; the CLI generates them for you.
✔ First-class container image support
Console apps can build container images without Dockerfiles:
dotnet publish /p:PublishProfile=DefaultContainer
Minor detail, significant quality-of-life upgrade.
✔ Tooling improvements
- One-shot execution: dotnet tool exec
- The new dnx script
- Better platform-specific tool support
- CLI introspection with --cli-schema
Nothing flashy, but everything feels more “grown up.”
Minor detail, significant quality-of-life upgrade.
✔ Tooling improvements
- One-shot execution: dotnet tool exec
- The new dnx script
- Better platform-specific tool support
- CLI introspection with --cli-schema
Nothing flashy, but everything feels more “grown up.”
1. Extension Blocks: the most prominent feature in C# 14
You’ve probably used extension methods for years. And you’ve probably also wished you could:
- add extension properties
- group related extensions cleanly
- add caching to extensions
Now you can.
Here’s what the old world looked like:
public static bool IsEmpty(this IEnumerable
items) =>*
!items.Any();
Here’s the new world:
extension
{
public bool IsEmpty => !items.Any();
}
Inside this extension block, you can define:
- extension properties
- extension instance methods
- extension static members
- private fields for memoization
Yes, private fields.
Meaning you can cache expensive operations:
This is huge.
If you’ve ever written helper classes, wrappers, or utility extensions, you’re going to love extension blocks. They’re clean. They’re natural. They make C# feel more modern.
extension(IEnumerable items)
{
private List? _cached;
public List Materialized => _cached ??= items.ToList();
}
2. Field-backed properties (field keyword)
This one eliminates a ton of boilerplate.
For years, a property with a custom setter required a private variable:
private string _name;
public string Name
{
get => _name;
set => _name = value ?? throw new ArgumentNullException();
}
Now
public string Name
{
get;
set => field = value ?? throw new ArgumentNullException();
}
Small feature. Big improvement in code clarity.
This is especially nice for:
- lazy initialization
- validation
- side-effect logic
- incremental setters
3. Null conditional assignment is finally here
This one surprised me because I hadn’t realized how much I actually wanted it until I tried it.
user?.Profile = LoadProfile();
Previously, C# allowed ?. only on reads.
Now it works for writes too.
This significantly reduces code clutter in real-life projects.
4. nameof() works with unbound generic types
This is one of those features that seems small until you need it.
nameof(List<>)
Returns
"List"
No more hacks for logging, reflection, or analyzers.
5. Lambdas can use modifiers more naturally
C# now lets you use ref, out, and in in lambdas without full type declarations:
(text, out result) => int.TryParse(text, out result);
Cleaner and much closer to how regular methods work.
6. User-defined compound operators
You can now define operators like:
- +=
- -=
- *=
- /=
This is an excellent improvement for domain-driven types like:
- Money
- Quantity
- Duration
- Vector
7. Partial constructors and partial events
This is mainly aimed at people writing source generators, but it's a very welcome improvement.
You can now do:
public partial class User
{
public partial User(string name);
}
And implement it elsewhere.
Generators and hand-written code can now blend much more cleanly.
Should You Upgrade to .NET 10 and C# 14?
If you’re still on .NET 8 or 9, and you’ve been waiting for the next LTS release, yes, absolutely upgrade.
.NET 10 feels stable, well-thought-out, and noticeably smoother.
C# 14 introduces enough quality-of-life improvements that going back feels like a painful experience.
If you maintain enterprise apps or large codebases, these features can reduce boilerplate code, simplify extensions, and generally enhance the developer experience. I’m already migrating personal projects and will start upgrading a couple of commercial apps next.
Finally
.NET 10 and C# 14 aren’t flashy, and honestly, that’s what makes them good. They focus on:
- predictable upgrades
- meaningful performance gains
- quality-of-life improvements
- language features that remove friction
- cleaner extension patterns
- more intuitive property handling
It’s the kind of release that doesn’t break your workflow, it just improves it.
If you end up upgrading, or even experimenting with some of the new C# features, I’d love to hear what you think.
Member discussion