dotnet-native-aot
Full Native AOT compilation pipeline for .NET 8+ applications: PublishAot configuration, ILLink descriptor XML for
type preservation, reflection-free coding patterns, P/Invoke considerations, binary size optimization, self-contained
deployment with runtime-deps base images, and diagnostic analyzers (EnableAotAnalyzer/EnableTrimAnalyzer).
Version assumptions: .NET 8.0+ baseline. Native AOT for ASP.NET Core Minimal APIs and console apps shipped in
.NET 8. .NET 9 improved trimming warnings and library compat. .NET 10 enhanced request delegate generator and expanded
Minimal API AOT support.
Scope
- PublishAot MSBuild configuration (apps vs libraries)
- Diagnostic analyzers (EnableAotAnalyzer, EnableTrimAnalyzer)
- ILLink descriptor XML for type preservation
- Reflection-free coding patterns
- P/Invoke with LibraryImport source generation
- Binary size optimization and self-contained deployment
- ASP.NET Core Native AOT (Minimal APIs, CreateSlimBuilder)
Out of scope
- MAUI iOS/Mac Catalyst AOT pipeline -- see [skill:dotnet-maui-aot]
- AOT-first design patterns (source gen, DI, serialization) -- see [skill:dotnet-aot-architecture]
- Trim-safe library authoring -- see [skill:dotnet-trimming]
- WASM AOT for Blazor/Uno -- see [skill:dotnet-aot-wasm]
- Source generator authoring (Roslyn API) -- see [skill:dotnet-csharp-source-generators]
- DI container patterns -- see [skill:dotnet-csharp-dependency-injection]
- Serialization depth -- see [skill:dotnet-serialization]
- Container deployment orchestration -- see [skill:dotnet-containers]
Cross-references: [skill:dotnet-aot-architecture] for AOT-first design patterns, [skill:dotnet-trimming] for trim-safe
library authoring, [skill:dotnet-aot-wasm] for WebAssembly AOT, [skill:dotnet-maui-aot] for MAUI-specific AOT,
[skill:dotnet-containers] for runtime-deps base images, [skill:dotnet-serialization] for AOT-safe serialization,
[skill:dotnet-csharp-source-generators] for source gen as AOT enabler, [skill:dotnet-csharp-dependency-injection] for
AOT-safe DI, [skill:dotnet-native-interop] for general P/Invoke patterns and cross-platform library resolution.
PublishAot Configuration
Enabling Native AOT
<!-- App .csproj -->
<PropertyGroup>
<PublishAot>true</PublishAot>
</PropertyGroup>
```csharp
```bash
# Publish as Native AOT
dotnet publish -c Release -r linux-x64
# Publish for specific targets
dotnet publish -c Release -r win-x64
dotnet publish -c Release -r osx-arm64
```text
### MSBuild Properties: Apps vs Libraries
Apps and libraries use different MSBuild properties. Do not mix them.
**For applications** (console apps, ASP.NET Core Minimal APIs):
```xml
<PropertyGroup>
<!-- Enable Native AOT compilation on publish -->
<PublishAot>true</PublishAot>
<!-- Enable analyzers during development (not just publish) -->
<EnableAotAnalyzer>true</EnableAotAnalyzer>
<EnableTrimAnalyzer>true</EnableTrimAnalyzer>
</PropertyGroup>
```text
**For libraries** (NuGet packages, shared class libraries):
```xml
<PropertyGroup>
<!-- Declare the library is AOT-compatible (auto-enables analyzers) -->
<IsAotCompatible>true</IsAotCompatible>
<!-- Declare the library is trim-safe (auto-enables trim analyzer) -->
<IsTrimmable>true</IsTrimmable>
</PropertyGroup>
```text
`IsAotCompatible` and `IsTrimmable` automatically enable the AOT and trim analyzers respectively. Do not also set `PublishAot` in library projects -- libraries are not published as standalone executables.
---
## Diagnostic Analyzers
Enable AOT and trim analyzers during development to catch issues before publishing:
```xml
<PropertyGroup>
<EnableAotAnalyzer>true</EnableAotAnalyzer>
<EnableTrimAnalyzer>true</EnableTrimAnalyzer>
</PropertyGroup>
```text
### Analysis Without Publishing
Run analysis during `dotnet build` without a full publish:
```bash
# Analyze AOT compatibility without publishing
dotnet build /p:EnableAotAnalyzer=true /p:EnableTrimAnalyzer=true
# See per-occurrence warnings (not grouped by assembly)
dotnet build /p:EnableAotAnalyzer=true /p:EnableTrimAnalyzer=true /p:TrimmerSingleWarn=false
```text
This reports IL2xxx (trim) and IL3xxx (AOT) warnings without producing a native binary, enabling fast feedback during development.
### Common Diagnostic Codes
| Code | Category | Meaning |
|------|----------|---------|
| IL2026 | Trim | Member has `[RequiresUnreferencedCode]` -- may break after trimming |
| IL2046 | Trim | Trim attribute mismatch between base/derived types |
| IL2057-IL2072 | Trim | Various reflection usage that the trimmer cannot analyze |
| IL3050 | AOT | Member has `[RequiresDynamicCode]` -- generates code at runtime |
| IL3051 | AOT | `[RequiresDynamicCode]` attribute mismatch |
---
## ILLink Descriptors for Type Preservation
When code uses reflection that the trimmer cannot statically analyze, use ILLink descriptor XML to preserve types. **Do not use legacy RD.xml** -- it is a .NET Native/UWP format that is silently ignored by modern .NET AOT.
### ILLink Descriptor XML
```xml
<!-- ILLink.Descriptors.xml -->
<linker>
<!-- Preserve all public members of a type -->
<assembly fullname="MyApp">
<type fullname="MyApp.Models.LegacyConfig" preserve="all" />
<type fullname="MyApp.Services.PluginLoader">
<method name="LoadPlugin" />
</type>
</assembly>
<!-- Preserve an entire external assembly -->
<assembly fullname="IncompatibleLibrary" preserve="all" />
</linker>
```text
```xml
<!-- Register in .csproj -->
<ItemGroup>
<TrimmerRootDescriptor Include="ILLink.Descriptors.xml" />
</ItemGroup>
```csharp
### `[DynamicDependency]` Attribute
For targeted preservation in code (preferred over ILLink XML for small, localized cases):
```csharp
using System.Diagnostics.CodeAnalysis;
// Preserve a specific method
[DynamicDependency(nameof(LegacyConfig.Initialize), typeof(LegacyConfig))]
public void ConfigureApp() { /* ... */ }
// Preserve all public members
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(PluginBase))]
public void LoadPlugins() { /* ... */ }
```text
### When to Use Which
| Scenario | Approach |
|----------|----------|
| One or two methods/types | `[DynamicDependency]` attribute |
| Entire assembly or many types | ILLink descriptor XML |
| Third-party library not AOT-safe | ILLink descriptor XML or `<TrimmerRootAssembly>` |
| Your own code with analyzed reflection | Refactor to source generators (best long-term) |
---
## Reflection-Free Patterns
Native AOT works best with code that avoids runtime reflection entirely. Replace reflection patterns with compile-time alternatives.
| Reflection Pattern | AOT-Safe Replacement |
|-------------------|---------------------|
| `Activator.CreateInstance<T>()` | Factory method or explicit `new T()` |
| `Type.GetProperties()` for mapping | Mapperly source generator or manual mapping |
| `Assembly.GetTypes()` for DI scanning | Explicit `services.AddScoped<T>()` |
| `JsonSerializer.Deserialize<T>(json)` | `JsonSerializer.Deserialize(json, Context.Default.T)` |
| `MethodInfo.Invoke()` for dispatch | `switch` on type or interface dispatch |
See [skill:dotnet-aot-architecture] for comprehensive AOT-first design patterns.
---
## P/Invoke Considerations
P/Invoke (platform invoke) calls to native libraries generally work with Native AOT, but require attention:
### Direct P/Invoke (Preferred)
```csharp
// Direct P/Invoke -- AOT-compatible, no runtime marshalling overhead
[LibraryImport("libsqlite3", EntryPoint = "sqlite3_open")]
internal static partial int Sqlite3Open(
[MarshalAs(UnmanagedType.LPStr)] string filename,
out nint db);
```text
Use `[LibraryImport]` (.NET 7+) instead of `[DllImport]` -- it generates marshalling code at compile time via source generators, making it fully AOT-compatible.
### DllImport vs LibraryImport
| Attribute | AOT Compatibility | Marshalling |
|-----------|------------------|-------------|
| `[DllImport]` | Partial -- some marshalling requires runtime codegen | Runtime marshalling |
| `[LibraryImport]` | Full -- compile-time source gen | Compile-time marshalling |
```csharp
// Migrate from DllImport to LibraryImport
// Before:
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool CloseHandle(IntPtr hObject);
// After:
[LibraryImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static partial bool CloseHandle(IntPtr hObject);
```text
### Native Library Deployment
When publishing as Native AOT, native libraries (`.so`, `.dylib`, `.dll`) must be alongside the binary:
```xml
<ItemGroup>
<!-- Include native library in publish output -->
<NativeLibrary Include="libs/libcustom.so" />
</ItemGroup>
```text
---
## Size Optimization
### Binary Size Reduction Options
```xml
<PropertyGroup>
<PublishAot>true</PublishAot>
<!-- Strip debug symbols (significant size reduction) -->
<StripSymbols>true</StripSymbols>
<!-- Optimize for size over speed -->
<OptimizationPreference>Size</OptimizationPreference>
<!-- Enable invariant globalization (removes ICU data) -->
<InvariantGlobalization>true</InvariantGlobalization>
<!-- Remove stack trace strings (reduces size, harder debugging) -->
<StackTraceSupport>false</StackTraceSupport>
<!-- Remove EventSource/EventPipe (if not using diagnostics) -->
<EventSourceSupport>false</EventSourceSupport>
</PropertyGroup>
```text
### Typical Binary Sizes
| Configuration | Console App | ASP.NET Minimal API |
|--------------|-------------|---------------------|
| Default AOT | ~10-15 MB | ~15-25 MB |
| + StripSymbols | ~8-12 MB | ~12-20 MB |
| + Size optimization | ~6-10 MB | ~10-18 MB |
| + InvariantGlobalization | ~4-8 MB | ~8-15 MB |
### Size Analysis
```bash
# Analyze what contributes to binary size
dotnet publish -c Release -r linux-x64 /p:PublishAot=true
# Use sizoscope (community tool) for detailed size analysis
# https://github.com/AdrianEddy/sizoscope
```text
---
## Self-Contained Deployment with runtime-deps
Native AOT produces self-contained binaries that include the .NET runtime. Use the `runtime-deps` base image for minimal container size since the runtime is already embedded in the binary.
```dockerfile
# Build stage
FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build
WORKDIR /src
COPY . .
RUN dotnet publish -c Release -r linux-x64 -o /app/publish
# Runtime stage -- use runtime-deps, not aspnet or runtime
FROM mcr.microsoft.com/dotnet/runtime-deps:10.0-noble-chiseled AS runtime
WORKDIR /app
COPY --from=build /app/publish .
ENTRYPOINT ["./MyApp"]
```text
The `runtime-deps` image contains only OS-level dependencies (libc, OpenSSL, etc.) -- no .NET runtime. This is the smallest possible base image for AOT-published apps (~30 MB). See [skill:dotnet-containers] for full container patterns.
---
## ASP.NET Core Native AOT
### Minimal API Support (.NET 8+)
ASP.NET Core Minimal APIs support Native AOT. MVC controllers are **not** AOT-compatible (they rely on reflection for model binding, filters, and routing).
```csharp
var builder = WebApplication.CreateSlimBuilder(args);
// Use source-generated JSON context
builder.Services.ConfigureHttpJsonOptions(options =>
{
options.SerializerOptions.TypeInfoResolverChain.Insert(0, AppJsonContext.Default);
});
var app = builder.Build();
app.MapGet("/api/products/{id}", (int id) =>
Results.Ok(new Product(id, "Widget")));
app.Run();
## Detailed Examples
See [references/detailed-examples.md](references/detailed-examples.md) for complete code samples and advanced patterns.
1---2name: dotnet-native-aot3description: Publishes Native AOT binaries. PublishAot, ILLink descriptors, P/Invoke, size optimization.4license: MIT5targets: ['*']6category: performance7subcategory: aot8tags:9 - performance10 - dotnet11 - skill12 - aot13 - native14version: '1.0.0'15author: 'dotnet-agent-harness'16invocable: true17related_skills:18 - dotnet-aot-architecture19 - dotnet-trimming20 - dotnet-multi-targeting21 - dotnet-aot-wasm22claudecode:23 allowed-tools: ['Read', 'Grep', 'Glob', 'Bash', 'Write', 'Edit']24codexcli:25 short-description: '.NET skill guidance for aot tasks'26opencode:27 allowed-tools: ['Read', 'Grep', 'Glob', 'Bash', 'Write', 'Edit']28copilot: {}29geminicli: {}30antigravity: {}31---3233# dotnet-native-aot3435Full Native AOT compilation pipeline for .NET 8+ applications: `PublishAot` configuration, ILLink descriptor XML for36type preservation, reflection-free coding patterns, P/Invoke considerations, binary size optimization, self-contained37deployment with `runtime-deps` base images, and diagnostic analyzers (`EnableAotAnalyzer`/`EnableTrimAnalyzer`).3839**Version assumptions:** .NET 8.0+ baseline. Native AOT for ASP.NET Core Minimal APIs and console apps shipped in40.NET 8. .NET 9 improved trimming warnings and library compat. .NET 10 enhanced request delegate generator and expanded41Minimal API AOT support.4243## Scope4445- PublishAot MSBuild configuration (apps vs libraries)46- Diagnostic analyzers (EnableAotAnalyzer, EnableTrimAnalyzer)47- ILLink descriptor XML for type preservation48- Reflection-free coding patterns49- P/Invoke with LibraryImport source generation50- Binary size optimization and self-contained deployment51- ASP.NET Core Native AOT (Minimal APIs, CreateSlimBuilder)5253## Out of scope5455- MAUI iOS/Mac Catalyst AOT pipeline -- see [skill:dotnet-maui-aot]56- AOT-first design patterns (source gen, DI, serialization) -- see [skill:dotnet-aot-architecture]57- Trim-safe library authoring -- see [skill:dotnet-trimming]58- WASM AOT for Blazor/Uno -- see [skill:dotnet-aot-wasm]59- Source generator authoring (Roslyn API) -- see [skill:dotnet-csharp-source-generators]60- DI container patterns -- see [skill:dotnet-csharp-dependency-injection]61- Serialization depth -- see [skill:dotnet-serialization]62- Container deployment orchestration -- see [skill:dotnet-containers]6364Cross-references: [skill:dotnet-aot-architecture] for AOT-first design patterns, [skill:dotnet-trimming] for trim-safe65library authoring, [skill:dotnet-aot-wasm] for WebAssembly AOT, [skill:dotnet-maui-aot] for MAUI-specific AOT,66[skill:dotnet-containers] for `runtime-deps` base images, [skill:dotnet-serialization] for AOT-safe serialization,67[skill:dotnet-csharp-source-generators] for source gen as AOT enabler, [skill:dotnet-csharp-dependency-injection] for68AOT-safe DI, [skill:dotnet-native-interop] for general P/Invoke patterns and cross-platform library resolution.6970---7172## PublishAot Configuration7374### Enabling Native AOT7576````xml7778<!-- App .csproj -->79<PropertyGroup>80 <PublishAot>true</PublishAot>81</PropertyGroup>8283```csharp8485```bash8687# Publish as Native AOT88dotnet publish -c Release -r linux-x648990# Publish for specific targets91dotnet publish -c Release -r win-x6492dotnet publish -c Release -r osx-arm649394```text9596### MSBuild Properties: Apps vs Libraries9798Apps and libraries use different MSBuild properties. Do not mix them.99100**For applications** (console apps, ASP.NET Core Minimal APIs):101102```xml103104<PropertyGroup>105 <!-- Enable Native AOT compilation on publish -->106 <PublishAot>true</PublishAot>107108 <!-- Enable analyzers during development (not just publish) -->109 <EnableAotAnalyzer>true</EnableAotAnalyzer>110 <EnableTrimAnalyzer>true</EnableTrimAnalyzer>111</PropertyGroup>112113```text114115**For libraries** (NuGet packages, shared class libraries):116117```xml118119<PropertyGroup>120 <!-- Declare the library is AOT-compatible (auto-enables analyzers) -->121 <IsAotCompatible>true</IsAotCompatible>122 <!-- Declare the library is trim-safe (auto-enables trim analyzer) -->123 <IsTrimmable>true</IsTrimmable>124</PropertyGroup>125126```text127128`IsAotCompatible` and `IsTrimmable` automatically enable the AOT and trim analyzers respectively. Do not also set `PublishAot` in library projects -- libraries are not published as standalone executables.129130---131132## Diagnostic Analyzers133134Enable AOT and trim analyzers during development to catch issues before publishing:135136```xml137138<PropertyGroup>139 <EnableAotAnalyzer>true</EnableAotAnalyzer>140 <EnableTrimAnalyzer>true</EnableTrimAnalyzer>141</PropertyGroup>142143```text144145### Analysis Without Publishing146147Run analysis during `dotnet build` without a full publish:148149```bash150151# Analyze AOT compatibility without publishing152dotnet build /p:EnableAotAnalyzer=true /p:EnableTrimAnalyzer=true153154# See per-occurrence warnings (not grouped by assembly)155dotnet build /p:EnableAotAnalyzer=true /p:EnableTrimAnalyzer=true /p:TrimmerSingleWarn=false156157```text158159This reports IL2xxx (trim) and IL3xxx (AOT) warnings without producing a native binary, enabling fast feedback during development.160161### Common Diagnostic Codes162163| Code | Category | Meaning |164|------|----------|---------|165| IL2026 | Trim | Member has `[RequiresUnreferencedCode]` -- may break after trimming |166| IL2046 | Trim | Trim attribute mismatch between base/derived types |167| IL2057-IL2072 | Trim | Various reflection usage that the trimmer cannot analyze |168| IL3050 | AOT | Member has `[RequiresDynamicCode]` -- generates code at runtime |169| IL3051 | AOT | `[RequiresDynamicCode]` attribute mismatch |170171---172173## ILLink Descriptors for Type Preservation174175When code uses reflection that the trimmer cannot statically analyze, use ILLink descriptor XML to preserve types. **Do not use legacy RD.xml** -- it is a .NET Native/UWP format that is silently ignored by modern .NET AOT.176177### ILLink Descriptor XML178179```xml180181<!-- ILLink.Descriptors.xml -->182<linker>183 <!-- Preserve all public members of a type -->184 <assembly fullname="MyApp">185 <type fullname="MyApp.Models.LegacyConfig" preserve="all" />186 <type fullname="MyApp.Services.PluginLoader">187 <method name="LoadPlugin" />188 </type>189 </assembly>190191 <!-- Preserve an entire external assembly -->192 <assembly fullname="IncompatibleLibrary" preserve="all" />193</linker>194195```text196197```xml198199<!-- Register in .csproj -->200<ItemGroup>201 <TrimmerRootDescriptor Include="ILLink.Descriptors.xml" />202</ItemGroup>203204```csharp205206### `[DynamicDependency]` Attribute207208For targeted preservation in code (preferred over ILLink XML for small, localized cases):209210```csharp211212using System.Diagnostics.CodeAnalysis;213214// Preserve a specific method215[DynamicDependency(nameof(LegacyConfig.Initialize), typeof(LegacyConfig))]216public void ConfigureApp() { /* ... */ }217218// Preserve all public members219[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(PluginBase))]220public void LoadPlugins() { /* ... */ }221222```text223224### When to Use Which225226| Scenario | Approach |227|----------|----------|228| One or two methods/types | `[DynamicDependency]` attribute |229| Entire assembly or many types | ILLink descriptor XML |230| Third-party library not AOT-safe | ILLink descriptor XML or `<TrimmerRootAssembly>` |231| Your own code with analyzed reflection | Refactor to source generators (best long-term) |232233---234235## Reflection-Free Patterns236237Native AOT works best with code that avoids runtime reflection entirely. Replace reflection patterns with compile-time alternatives.238239| Reflection Pattern | AOT-Safe Replacement |240|-------------------|---------------------|241| `Activator.CreateInstance<T>()` | Factory method or explicit `new T()` |242| `Type.GetProperties()` for mapping | Mapperly source generator or manual mapping |243| `Assembly.GetTypes()` for DI scanning | Explicit `services.AddScoped<T>()` |244| `JsonSerializer.Deserialize<T>(json)` | `JsonSerializer.Deserialize(json, Context.Default.T)` |245| `MethodInfo.Invoke()` for dispatch | `switch` on type or interface dispatch |246247See [skill:dotnet-aot-architecture] for comprehensive AOT-first design patterns.248249---250251## P/Invoke Considerations252253P/Invoke (platform invoke) calls to native libraries generally work with Native AOT, but require attention:254255### Direct P/Invoke (Preferred)256257```csharp258259// Direct P/Invoke -- AOT-compatible, no runtime marshalling overhead260[LibraryImport("libsqlite3", EntryPoint = "sqlite3_open")]261internal static partial int Sqlite3Open(262 [MarshalAs(UnmanagedType.LPStr)] string filename,263 out nint db);264265```text266267Use `[LibraryImport]` (.NET 7+) instead of `[DllImport]` -- it generates marshalling code at compile time via source generators, making it fully AOT-compatible.268269### DllImport vs LibraryImport270271| Attribute | AOT Compatibility | Marshalling |272|-----------|------------------|-------------|273| `[DllImport]` | Partial -- some marshalling requires runtime codegen | Runtime marshalling |274| `[LibraryImport]` | Full -- compile-time source gen | Compile-time marshalling |275276```csharp277278// Migrate from DllImport to LibraryImport279// Before:280[DllImport("kernel32.dll", SetLastError = true)]281static extern bool CloseHandle(IntPtr hObject);282283// After:284[LibraryImport("kernel32.dll", SetLastError = true)]285[return: MarshalAs(UnmanagedType.Bool)]286internal static partial bool CloseHandle(IntPtr hObject);287288```text289290### Native Library Deployment291292When publishing as Native AOT, native libraries (`.so`, `.dylib`, `.dll`) must be alongside the binary:293294```xml295296<ItemGroup>297 <!-- Include native library in publish output -->298 <NativeLibrary Include="libs/libcustom.so" />299</ItemGroup>300301```text302303---304305## Size Optimization306307### Binary Size Reduction Options308309```xml310311<PropertyGroup>312 <PublishAot>true</PublishAot>313314 <!-- Strip debug symbols (significant size reduction) -->315 <StripSymbols>true</StripSymbols>316317 <!-- Optimize for size over speed -->318 <OptimizationPreference>Size</OptimizationPreference>319320 <!-- Enable invariant globalization (removes ICU data) -->321 <InvariantGlobalization>true</InvariantGlobalization>322323 <!-- Remove stack trace strings (reduces size, harder debugging) -->324 <StackTraceSupport>false</StackTraceSupport>325326 <!-- Remove EventSource/EventPipe (if not using diagnostics) -->327 <EventSourceSupport>false</EventSourceSupport>328</PropertyGroup>329330```text331332### Typical Binary Sizes333334| Configuration | Console App | ASP.NET Minimal API |335|--------------|-------------|---------------------|336| Default AOT | ~10-15 MB | ~15-25 MB |337| + StripSymbols | ~8-12 MB | ~12-20 MB |338| + Size optimization | ~6-10 MB | ~10-18 MB |339| + InvariantGlobalization | ~4-8 MB | ~8-15 MB |340341### Size Analysis342343```bash344345# Analyze what contributes to binary size346dotnet publish -c Release -r linux-x64 /p:PublishAot=true347348# Use sizoscope (community tool) for detailed size analysis349# https://github.com/AdrianEddy/sizoscope350351```text352353---354355## Self-Contained Deployment with runtime-deps356357Native AOT produces self-contained binaries that include the .NET runtime. Use the `runtime-deps` base image for minimal container size since the runtime is already embedded in the binary.358359```dockerfile360361# Build stage362FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build363WORKDIR /src364COPY . .365RUN dotnet publish -c Release -r linux-x64 -o /app/publish366367# Runtime stage -- use runtime-deps, not aspnet or runtime368FROM mcr.microsoft.com/dotnet/runtime-deps:10.0-noble-chiseled AS runtime369WORKDIR /app370COPY --from=build /app/publish .371ENTRYPOINT ["./MyApp"]372373```text374375The `runtime-deps` image contains only OS-level dependencies (libc, OpenSSL, etc.) -- no .NET runtime. This is the smallest possible base image for AOT-published apps (~30 MB). See [skill:dotnet-containers] for full container patterns.376377---378379## ASP.NET Core Native AOT380381### Minimal API Support (.NET 8+)382383ASP.NET Core Minimal APIs support Native AOT. MVC controllers are **not** AOT-compatible (they rely on reflection for model binding, filters, and routing).384385```csharp386387var builder = WebApplication.CreateSlimBuilder(args);388389// Use source-generated JSON context390builder.Services.ConfigureHttpJsonOptions(options =>391{392 options.SerializerOptions.TypeInfoResolverChain.Insert(0, AppJsonContext.Default);393});394395var app = builder.Build();396397app.MapGet("/api/products/{id}", (int id) =>398 Results.Ok(new Product(id, "Widget")));399400app.Run();401402## Detailed Examples403404See [references/detailed-examples.md](references/detailed-examples.md) for complete code samples and advanced patterns.