.NET Container Images Explained: Chiselled, Alpine, and More

Microsoft publishes several variants of .NET container images, and choosing the right one has a meaningful impact on image size, security posture, and startup time. This article breaks down the options.

The Image Family

All official .NET images are published to the Microsoft Container Registry (MCR). There are four base image types:

Image Purpose Includes
sdk Building and publishing .NET SDK, runtime, tools
aspnet Running ASP.NET Core apps ASP.NET Core + .NET runtime
runtime Running console/.NET apps .NET runtime only
runtime-deps Running self-contained apps Native OS dependencies only

You should never ship an sdk image to production. Use the smallest image that your application actually needs.

Standard (Debian-Based) Images

The default images are based on Debian. They include a full Linux userland with a shell, package manager, and common utilities.

Dockerfile
FROM mcr.microsoft.com/dotnet/aspnet:9.0

This pulls the Debian-based variant. It's the most compatible option and a safe default when you don't have specific size or security requirements. The ASP.NET runtime image is roughly 220 MB.

Alpine Images

Alpine Linux uses musl libc instead of glibc and strips out most utilities. The result is a significantly smaller image.

Dockerfile
FROM mcr.microsoft.com/dotnet/aspnet:9.0-alpine

The Alpine ASP.NET image is around 110 MB — roughly half the Debian variant. For most ASP.NET Core applications, Alpine works without issues. However, some native libraries assume glibc, so test thoroughly if you depend on native interop.

When publishing a self-contained app for Alpine, you need the correct runtime identifier:

Dockerfile
RUN dotnet publish -c Release -r linux-musl-x64 --self-contained -o /app/publish

Note the linux-musl-x64 RID — using linux-x64 will produce binaries linked against glibc, which will fail on Alpine.

Chiselled Images (Ubuntu-Based)

Chiselled images are Canonical's answer to minimal containers. They're based on Ubuntu but stripped down to only the files your application needs — no shell, no package manager, no /bin/bash.

Dockerfile
FROM mcr.microsoft.com/dotnet/aspnet:9.0-noble-chiseled

Chiselled images are:

The trade-off is debuggability. You cannot docker exec into a chiselled container and poke around because there's no shell. For production, this is generally a benefit. For debugging, you'll need to use logging, tracing, or attach a debug sidecar.

Chiselled + AOT

For the absolute smallest images, combine Native AOT with chiselled runtime-deps:

Dockerfile
FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build
WORKDIR /src
COPY . .
RUN dotnet publish src/MyApi/MyApi.csproj \
    -c Release \
    -r linux-x64 \
    -p:PublishAot=true \
    -o /app/publish

FROM mcr.microsoft.com/dotnet/runtime-deps:9.0-noble-chiseled
WORKDIR /app
COPY --from=build /app/publish .
ENTRYPOINT ["./MyApi"]

The resulting image can be as small as 30-50 MB. Native AOT compiles your application to a single native binary — no .NET runtime needed at runtime. The runtime-deps chiselled image provides only the minimal native libraries.

Not all .NET libraries support AOT, so check compatibility before adopting this approach.

Extra Variants

A few less common but useful variants:

Choosing the Right Image

Here's a practical decision tree:

  1. Do you need globalisation/ICU? Use -extra or standard Debian/Alpine.
  2. Do you need the smallest possible image? Use chiselled + AOT with runtime-deps.
  3. Do you need to exec into containers for debugging? Use standard Debian or Alpine.
  4. Are you running in production with no special requirements? Use chiselled.
  5. Default safe choice? Alpine is a good middle ground — small, secure, and debuggable.

Summary

The days of one-size-fits-all container images are gone. For .NET applications, start with Alpine or chiselled images and only move to the larger Debian variants if you have a specific compatibility need. The difference between a 220 MB image and a 40 MB image adds up across dozens of services and thousands of deployments.