Last updated: February 2026 -- .NET 10 GA (November 2025)
Sources: Breaking changes in .NET 10, ASP.NET Core 9 to 10 migration, EF Core 10 breaking changes
<PropertyGroup>
- <TargetFramework>net9.0</TargetFramework>
+ <TargetFramework>net10.0</TargetFramework>
</PropertyGroup>{
"sdk": {
- "version": "9.0.304"
+ "version": "10.0.100"
}
}All Microsoft.AspNetCore.*, Microsoft.EntityFrameworkCore.*, Microsoft.Extensions.*, and System.Net.Http.Json packages must be updated to 10.0.0 or later.
.NET 10 ships with C# 14. Set <LangVersion>14</LangVersion> or <LangVersion>latest</LangVersion>. New language features include extension members, the field keyword, and broader params collection support.
The WithOpenApi() extension methods are deprecated (diagnostic ASPDEPR002). Use the built-in AddOpenApi() / MapOpenApi() instead, which generates OpenAPI documents natively without requiring the Microsoft.AspNetCore.OpenApi package's WithOpenApi extension.
The OpenAPI library used internally has been upgraded to Microsoft.OpenApi 2.0 GA. If you directly reference Microsoft.OpenApi types (e.g., in OpenAPI document transformers), review API changes in the 2.0 release.
Cookie-based authentication no longer issues redirects for unauthenticated/unauthorized requests to API endpoints. Previously, the handler had special logic to detect API endpoints and issue redirects. This has been removed -- API endpoints now return 401/403 directly.
- NavLinkMatch.All now ignores query strings when matching URLs.
- HttpClient streaming is enabled by default in Blazor WebAssembly.
- Fragment deprecated in favor of
NotFoundPage. - blazor.boot.json has been inlined into the
dotnet.jsscript. - BlazorCacheBootResources MSBuild property removed -- all client-side files are now fingerprinted and cached by the browser.
- Standalone Blazor WASM environment is now set via
<WasmApplicationEnvironmentName>MSBuild property instead oflaunchSettings.json.
Source generators that are not incremental are now obsoleted. If you maintain custom source generators, they must be rewritten as incremental source generators.
When running EF tools (dotnet ef) on a project with <TargetFrameworks> (plural), you must specify --framework:
dotnet ef migrations add MyMigration --framework net10.0
dotnet ef database update --framework net10.0Without this, EF tools throw: "The project targets multiple frameworks. Use the --framework option to specify which target framework to use."
EF now injects an Application Name into connection strings that do not already have one. This can cause separate connection pools when mixing EF and non-EF data access (Dapper, raw ADO.NET), potentially triggering distributed transaction escalation inside TransactionScope.
Mitigation: Explicitly set Application Name in your connection string.
If you use UseAzureSql() or configure compatibility level 170+, EF maps JSON columns to the native json type instead of nvarchar(max). Upgrading generates a migration that alters existing columns.
Mitigation: Set compatibility level below 170, or explicitly configure HasColumnType("nvarchar(max)") on affected properties.
Contains() queries now translate to WHERE [Id] IN (@p1, @p2, @p3) instead of OPENJSON(@json). This provides better cardinality estimates but may affect query plan caching for large collections.
Mitigation: Configure UseParameterizedCollectionMode(ParameterTranslationMode.Parameter) to revert to JSON-based translation, or use EF.Parameter(ids) per query.
ExecuteUpdate/ExecuteUpdateAsync now accepts a Func<...> instead of Expression<Func<...>>. Code that built expression trees dynamically for the setters argument will no longer compile but can be replaced with simpler imperative code using if statements inside the lambda.
Complex type column names are now uniquified by appending a number when duplicates exist. Nested complex type properties use the full path in column names (e.g., Complex_NestedComplex_Property instead of NestedComplex_Property).
Mitigation: Explicitly configure column names with HasColumnName() if you need to preserve existing names.
Three related changes affect SQLite DateTime handling:
GetDateTimeOffseton timestamps without an offset now assumes UTC (was local time).- Writing
DateTimeOffsetinto REAL columns now converts to UTC first. GetDateTimeon timestamps with an offset now returns UTC withDateTimeKind.Utc.
Mitigation: Set AppContext.SetSwitch("Microsoft.Data.Sqlite.Pre10TimeZoneHandling", true) to revert temporarily.
C# 14 may select different overloads when Span<T> / ReadOnlySpan<T> overloads are available. This is a behavioral change that can affect method dispatch without compile errors.
BufferedStream.WriteByte no longer flushes the buffer implicitly. Code relying on single-byte writes triggering flushes must call Flush() explicitly.
System.Linq.AsyncEnumerable is now part of the core libraries. If you have a NuGet reference to a third-party System.Linq.Async package, you may encounter ambiguous reference errors.
Mitigation: Remove the third-party System.Linq.Async package reference if present.
The default trace context propagator now uses the W3C standard. If you depend on the previous propagation format, configure your ActivitySource explicitly.
FilePatternMatch.Stem is now non-nullable. Code that null-checks this property may produce compiler warnings.
The runtime no longer installs default handlers for SIGTERM. If your application relies on graceful shutdown via SIGTERM, ensure you register handlers explicitly (e.g., via IHostApplicationLifetime).
BackgroundService now runs the entirety of ExecuteAsync as a Task. Previously, only the part after the first await ran asynchronously. If your ExecuteAsync does synchronous work before the first await, it now runs on a thread pool thread instead of blocking startup.
Configuration now preserves null values instead of removing keys with null values. Code that checks for key existence to detect "unset" values may behave differently.
The console logger no longer duplicates the message in JSON output mode. If you parse console log output, adjust your parsing logic.
ProviderAliasAttribute moved to Microsoft.Extensions.Logging.Abstractions. If you reference it by assembly-qualified name, update accordingly.
dotnet new sln now creates .slnx files instead of .sln. Existing .sln files continue to work. If your tooling does not support .slnx, use dotnet new sln --format sln explicitly.
NuGet audit now checks transitive packages by default. This may surface new security warnings for transitive dependencies.
A <PackageReference> without a Version attribute now raises error NU1015 unless you are using Central Package Management (Directory.Packages.props).
Single-file published apps no longer search the executable directory for native libraries by default. Use DllImportSearchPath.AssemblyDirectory explicitly if needed.
The default .NET container base images now use Ubuntu instead of Debian. This may affect applications that depend on Debian-specific packages or paths.
System.Text.Json now validates that serialized property names are unique within a type. If you have properties that serialize to the same JSON name (e.g., via [JsonPropertyName]), this now throws at serialization time.
XmlSerializer now serializes properties marked with [Obsolete]. Previously, these were silently skipped.
.NET 10 requires OpenSSL 1.1.1+ on Unix/Linux. Older OpenSSL versions are no longer supported.
OpenSSL-based cryptographic primitives are no longer supported on macOS. Use the platform's native cryptography APIs.
- Update
TargetFrameworktonet10.0 - Update
global.jsonSDK version to10.0.100 - Update all
Microsoft.*package references to 10.0.x - Search for
WithOpenApi()calls and migrate to built-in OpenAPI - Add
--frameworkto any EF tooling scripts for multi-targeted projects - Set explicit
Application Namein connection strings if mixing EF + raw ADO.NET - Check for
System.Linq.AsyncNuGet references (now built-in) - Review
System.Text.Jsonserialized types for property name conflicts - Verify SQLite
DateTime/DateTimeOffsethandling if using Microsoft.Data.Sqlite - Test container builds (base image changed from Debian to Ubuntu)
- Update CI scripts if they reference
.slnfiles explicitly (new default is.slnx)