Start Debugging

The performance and Native AOT cheat sheet

Measure first, then pick the knob.

This pillar collects everything on the site about making code faster and smaller - profiling before you guess, allocation and Span<T> work, caching, the JIT and compression changes in the .NET 11 cycle, and the constraints Native AOT puts on your code.

What to read first

Measure first: profiling with dotnet-trace and diagnosing a managed memory leak with gcdump and dump are the two loops worth learning. Before you tune anything, tiered compilation and PGO explain what the runtime already does for free - the newest example is the JIT devirtualizing generic virtual methods.

For allocation, what Span<T> actually speeds up leads and List vs Span vs ReadOnlySpan picks the type. Shipping smaller? Native AOT vs ReadyToRun vs JIT settles the fork, what Native AOT costs you is the honest ledger, and trim-safe code is the discipline; the failure you’ll hit first is reflection-based serialization disabled. On the server, HybridCache vs IMemoryCache vs IDistributedCache and detecting N+1 queries remove more time than any micro-optimisation.

What’s on this page

The list below auto-collects posts tagged with any of: performance, native-aot - which pulls in the Flutter and Dart performance posts too. Newest first.

Companion pillars: async and concurrency and the .NET 11 tracker.

Index (82 posts)

2026 / 09

2026 / 08

2026 / 07

  • Fix: Reflection-based serialization has been disabled for this application

    This InvalidOperationException means PublishTrimmed or PublishAot flipped JsonSerializerIsReflectionEnabledByDefault to false. Fix it with a source-generated JsonSerializerContext.

  • How to build a Flutter web app with WebAssembly using flutter build web --wasm

    A complete guide to shipping a Flutter web app compiled to WebAssembly on Flutter 3.44: what the two emitted builds look like, why Firefox and Safari still get JavaScript because of the loader's wasmAllowList, migrating off dart:html for dart2wasm, the COOP/COEP headers that decide whether skwasm runs multi-threaded, and how to prove at runtime which build the browser actually loaded.

  • How to diagnose a managed memory leak with dotnet-gcdump and dotnet-dump

    A complete workflow for finding a managed memory leak in .NET 11: confirm growth with dotnet-counters, take two gcdumps and diff them, then collect a dump and use dumpheap, gcroot, and objsize in dotnet-dump analyze to find what is still holding the reference.

  • WebApplication.CreateBuilder vs CreateSlimBuilder vs CreateEmptyBuilder in ASP.NET Core 11

    Use CreateBuilder for a normal app, CreateSlimBuilder when you publish trimmed or Native AOT behind a TLS proxy, and CreateEmptyBuilder only when you want to register every service yourself. Here is the feature matrix and the gotchas that force the call.

  • Output caching vs response caching in ASP.NET Core 11: which should you use?

    Output caching is the right default for almost every server-side app in ASP.NET Core 11. Response caching only wins when your goal is to steer browser and proxy caches through HTTP headers. Here is the decision, with a feature matrix and the gotchas that force the call.

  • How to add response compression to an ASP.NET Core 11 API

    A complete guide to response compression in ASP.NET Core 11: AddResponseCompression and UseResponseCompression, the new built-in Zstandard provider alongside Brotli and Gzip, compression levels, EnableForHttps and the CRIME/BREACH risk, custom MIME types, middleware ordering, and when to let the reverse proxy do it instead.

  • How to add output caching to a minimal API in ASP.NET Core 11

    A complete, working guide to output caching in an ASP.NET Core 11 minimal API: AddOutputCache and UseOutputCache, CacheOutput on endpoints and MapGroup, named and base policies, Expire, VaryByQuery and VaryByHeader, tag-based eviction with EvictByTagAsync, cache stampede protection, ETag revalidation, and a Redis backing store.

  • .NET 11 Runtime Async Drops the EnablePreviewFeatures Flag

    As the .NET 11 previews progress toward the November release, Runtime Async has graduated: net11.0 projects opt in with a single MSBuild property, and the runtime libraries themselves now ship compiled on it.

  • What is PGO in .NET and do I need to opt in?

    PGO (profile-guided optimization) lets the .NET JIT specialize hot code for the types and branches your workload actually hits. Dynamic PGO has been on by default since .NET 8, so on .NET 8 and later you do not need to opt in. Here is what it does, how to see its effect, and the rare cases where you touch the knob.

  • What is tiered compilation and how do I reason about it?

    Tiered compilation lets the .NET JIT compile every method twice: once fast and unoptimized to get your app running, then again with full optimizations once the runtime knows a method is hot. Here is how tier 0, tier 1, on-stack replacement, and Dynamic PGO fit together, and how to observe and tune them.

  • What is trim-safe code and how do I write it?

    Trim-safe code is code the .NET trimmer can statically prove is reachable, so it survives when unused code is removed from a self-contained app. This is the practical guide: turn on the analyzer, drive every IL2xxx warning to zero, annotate reflection with DynamicallyAccessedMembers, propagate RequiresUnreferencedCode to public APIs, and replace unanalyzable patterns with source generators.

  • SkiaSharp 4.0 Ships Stable: 24% Faster GPU Rendering and a Cleaned-Up API

    SkiaSharp 4.148.0 is the first stable v4 release. GPU-heavy UIs render up to 24% faster, CPU shaders run ~6x faster, and the legacy API surface is finally retired. Here is what upgrading actually costs you.

2026 / 06

2026 / 05

2026 / 04

2026 / 02

2026 / 01

2025 / 04

2025 / 01

  • .NET Performance: ToList vs ToArray

    .NET 9 significantly improves ToArray performance using InlineArray, making it faster and more memory-efficient than ToList. See benchmarks comparing .NET 8 vs .NET 9.

All pillars Home