What is the difference between JIT and AOT compilation in .NET?

.NET Framework & CLR Runtime Advanced 3–5 Yrs5+ Yrs Conceptual 1 min read

Quick Answer

JIT (Just-In-Time) compiles IL to native code at run time, the first time each method executes, and can re-optimise hot methods (tiered compilation). AOT (Ahead-Of-Time) compiles to native code at build time. Native AOT produces a small, fast-starting, self-contained binary with no JIT — at the cost of no runtime code generation and some reflection limits.

JIT compiles the intermediate language to machine code on the fly — the first time a method runs — and with tiered compilation it can recompile the hot methods with heavier optimisation once it sees them running a lot. The trade-off is startup cost and the memory the JIT itself uses. AOT compiles everything to native code at build time. Native AOT gives you a small self-contained executable that starts almost instantly with no JIT, which is great for CLI tools and cold-start-sensitive serverless functions. The cost is that you lose runtime code generation and a lot of reflection, so libraries that rely on those need source generators instead.

  • JIT — flexible, adapts to the actual CPU and runtime profile; downside is startup cost (first call compiles) and memory for the compiler.
  • Tiered compilation — a quick tier-0 compile first, then a heavily optimised tier-1 for methods that run a lot. On-stack replacement handles long-running methods.
  • ReadyToRun (R2R) — a hybrid: precompiled native code shipped alongside IL, so startup skips most JIT but the JIT can still kick in.
  • Native AOT — full ahead-of-time, no runtime JIT, trimmed. Best for CLI tools, serverless / cold-start-sensitive services, and constrained environments. Restrictions: no dynamic loading, limited reflection, no runtime IL emit (so some serializers / DI need source generators).