What’s New in EF Core 9 — What You Should Actually Care About

December 9, 2025 · Asad Ali

EF Core 9 launched in November 2024. It’s a “Short-Term Support” (STS) release — but with enough new features, performance optimisations, and provider updates that most serious projects should pay attention. In this post I walk you through the changes that matter operationally, the real gains (and tradeoffs), and how to approach upgrading existing systems.

Target platforms & support window

EF Core 9 targets .NET 8 (its LTS runtime) — though you can also use it with .NET 9. :contentReference[oaicite:1]{index=1}

Since it’s STS, support ends November 10, 2026. :contentReference[oaicite:2]{index=2}

Big story #1: First-class support for document & cloud-native scenarios (especially Azure Cosmos DB / NoSQL)

If you’ve ever tried to use EF for Cosmos DB in a “real” multi-tenant, partitioned, JSON-document scenario — you’ll appreciate how far EF Core 9 moves the provider forward. The provider has been significantly rewritten. :contentReference[oaicite:4]{index=4}

  • Partition-key aware queries: EF now reliably identifies comparisons against the partition key in LINQ, lifts them out, and ensures queries go only to the relevant partition. That reduces RU consumption and cost — a meaningful win for large-scale Cosmos workloads. :contentReference[oaicite:5]{index=5}
  • Hierarchical partition keys: If your container uses composite/hierarchical partition keys (e.g. TenantId + UserId + SomeShardKey), EF 9 lets you map them cleanly. That opens up solid multi-tenant and shard-by-user patterns. :contentReference[oaicite:6]{index=6}
  • Better JSON mapping / document-friendly modelling: The default JSON generated for documents is more natural. For example, the `id` property now holds only the key value (not a mangled type+id string), and the discriminator field is renamed to `$type` — aligning with common JSON-polymorphism conventions. That makes interoperability with other JSON tools and non-.NET services easier. :contentReference[oaicite:7]{index=7}
  • Vector similarity search (preview): For those building AI / semantic-search capabilities on top of Cosmos DB, EF 9 enables vector properties + new query translation. This can remove a separate vector-DB from your stack (e.g. no need for Pinecone or similar if Cosmos + EF meets your scale). :contentReference[oaicite:8]{index=8}
  • Efficient pagination: Rather than doing expensive Skip/Take on large result sets, you can now use continuation-token based paging with a new ToPageAsync API — more efficient and cost-effective for Cosmos DB. :contentReference[oaicite:9]{index=9}
  • Safer raw SQL via `FromSql`: If you need to drop into raw SQL for advanced queries, the newer `FromSql` API ensures parameters are properly handled, reducing risk of injection compared to older `FromSqlRaw` use. :contentReference[oaicite:10]{index=10}

My take: If you run cloud-native or polyglot apps (especially with Cosmos/NoSQL), EF Core 9 finally begins to deliver what the “EF for documents” promise has always hinted at. But upgrading existing Cosmos-based applications may require attention — especially if they relied on old id/discriminator conventions.

Big story #2: Smarter SQL translation, more efficient relational queries

EF Core 9 isn’t just about NoSQL — relational providers and SQL translation also get real wins. For teams using SQL Server, PostgreSQL, or any relational DB, the following improvements matter in real-world workloads: :contentReference[oaicite:11]{index=11}

  • Complex-type grouping & bulk updates: You can now `GroupBy` on complex/value-object types, and use `ExecuteUpdate` (or `ExecuteUpdateAsync`) to update complex type properties in bulk. That simplifies patterns involving value-objects and reduces boilerplate SQL. :contentReference[oaicite:12]{index=12}
  • Pruned SQL: fewer JOINs, cleaner projections: EF’s SQL generator is smarter — it removes unnecessary JOINs, avoids projecting unneeded columns, and generally produces more compact SQL. In one of my past systems, this would have reduced cross-server network traffic and improved performance. :contentReference[oaicite:13]{index=13}
  • Better translation for `Math.Min`/`Math.Max`, `GREATEST`/`LEAST`, and primitive-collection members: If your logic uses min/max or operates on collections of primitives, EF 9 can often translate them directly to SQL in a performant way instead of doing client-side evaluation — which reduces memory usage and latency. :contentReference[oaicite:14]{index=14}

My take: These improvements matter most in high-traffic systems where every query and join counts. Compact SQL + fewer round-trips = less CPU, less latency, fewer surprises under load.

Under-the-hood advance: Experimental AOT & Query Precompilation

EF Core 9 introduces early support for .NET NativeAOT + query precompilation. The idea: LINQ queries are compiled ahead-of-time into interceptor code, embedding SQL + materialization logic — so at runtime your app has minimal startup overhead. :contentReference[oaicite:16]{index=16}

This matters if you’re building serverless, microservice-per-function, or container-based workloads where startup time can directly affect resource usage or cold-start latency. That said — the EF team cautions that this is still experimental. :contentReference[oaicite:17]{index=17}

Warning: Don’t treat AOT + precompiled queries as production-ready yet. Test carefully under realistic load before relying on this for mission-critical services.

Breaking changes & gotchas — read carefully before upgrading

With new features come some changes you must know about. I’ve learnt the hard way — upgrading without reviewing breaking notes caused subtle production bugs. Here are the ones you need to pay attention to: :contentReference[oaicite:18]{index=18}

  • Value converters & nullability propagation now stricter: EF will now throw if you define conversion methods with mismatched argument / null-propagation arrays. If you used private methods for converters, upgrade may break — make them public or internal. :contentReference[oaicite:19]{index=19}
  • Old JSON document formats (Cosmos) are not compatible by default: Because EF 9 changed default behavior for `id` and discriminator (`$type`) fields, older documents may not be readable unless you enable legacy compatibility APIs. :contentReference[oaicite:20]{index=20}
  • SQL translation behavior changed — some edge-case queries might break: Because the SQL generator is more aggressive in pruning and rewriting, queries that previously worked (but were inefficient) may now behave differently. Always test query behavior after upgrading.

What I’d do tomorrow if I manage the data layer of a live .NET service

  1. Audit all existing converters, raw SQL usages, and custom translation logic. Make sure value converters are public/internal; don’t rely on private methods or legacy JSON-document behavior if you use Cosmos. Test thoroughly before upgrade.
  2. For relational workloads (SQL Server / PostgreSQL): refactor heavy read/update patterns to leverage grouping + `ExecuteUpdate` + better translation. Clean up LINQ queries, remove manual bulk-update loops — EF 9 can handle a lot of that efficiently now.
  3. If using Cosmos/NoSQL or building multi-tenant apps: consider switching to EF + Cosmos with hierarchical partition keys + vector-search (for AI/semantic workloads) — but only after validating query compat & RU usage.
  4. For microservices / serverless / containers: experiment with NativeAOT + query precompilation to reduce cold-start latency. But keep it in a controlled environment until the EF NativeAOT story matures.

EF Core 9 isn’t a “patch” — it’s a meaningful evolution. Whether you care most about relational performance, cloud-native JSON/NoSQL support, or startup optimization for microservices — there are wins. As always, though, pay attention to breaking changes and test thoroughly.

— Asad