About dotnet-dockerfile
.NET Dockerfile Generator is a skill for generating multi-stage Dockerfiles for .NET applications. It helps developers select an image and deployment pattern based on the .NET version and application type, including options such as chiseled images and Native AOT.
Key features
- 01Determine .NET version and application type
- 02Select standard, chiseled, or Native AOT patterns
- 03Generate multi-project solution build patterns
- 04Support self-contained deployment guidance
- 05Provide cache, digest-pinning, and verification guidance
Use cases
- 01Create a Dockerfile for an ASP.NET Core app
- 02Containerize a multi-project .NET solution
- 03Choose an image for Native AOT publishing
Install
Copy the command and run it in a terminal.
npx skills add https:/ / github.com/ jkappers/ agent-skills --skill dotnet-dockerfileAfter installing, type/dotnet-dockerfilein Claude Code to confirm it loaded.
Details
From the project README.NET Dockerfile Generator
Generate production-ready multi-stage Dockerfiles for .NET applications.
Workflow
- Determine .NET version (8, 9, or 10) from project file or ask user
- Identify project type: ASP.NET Core web app, API, worker service, or console app
- Locate project file path (e.g.,
src/MyApp/MyApp.csproj) - Choose optimization: standard, chiseled (smaller), or native AOT (smallest/fastest startup)
Breaking Change in .NET 10: Ubuntu is now the default Linux distribution for all .NET container images. Debian images are no longer provided. Tags like
10.0,10.0-noble, and10.0-noble-chiseledall use Ubuntu 24.04 "Noble Numbat".
Image Selection Guide
| Scenario | Runtime Image | Compressed Size |
|---|---|---|
| Standard ASP.NET | aspnet:10.0 | ~92 MB |
| Smaller footprint | aspnet:10.0-alpine | ~52 MB |
| Production (recommended) | aspnet:10.0-noble-chiseled | ~53 MB |
| Azure Linux distroless | aspnet:10.0-azurelinux3.0-distroless | ~55 MB |
| Self-contained | runtime-deps:10.0-noble-chiseled | ~22 MB |
| Native AOT | runtime-deps:10.0-noble-chiseled | ~12 MB |
Chiseled images: Ubuntu-based, no shell, no package manager, non-root by default. Recommended for production.
Azure Linux distroless: Alternative to chiseled with Microsoft supply chain security. Similar benefits: no shell, non-root by default.
Standard Pattern
# syntax=docker/dockerfile:1
FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build
WORKDIR /src
# Copy project files and restore (cache layer)
COPY *.csproj ./
RUN dotnet restore
# Copy source and publish
COPY . .
RUN dotnet publish -c Release -o /app/publish
# Runtime
FROM mcr.microsoft.com/dotnet/aspnet:10.0-noble-chiseled AS production
WORKDIR /app
COPY --from=build /app/publish .
USER app
EXPOSE 8080
ENTRYPOINT ["dotnet", "MyApp.dll"]
Multi-Project Solution Pattern
For solutions with multiple projects, copy all .csproj files first:
FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build
WORKDIR /src
# Copy solution and project files (cache layer)
COPY *.sln ./
COPY src/MyApp/*.csproj ./src/MyApp/
COPY src/MyApp.Core/*.csproj ./src/MyApp.Core/
COPY tests/MyApp.Tests/*.csproj ./tests/MyApp.Tests/
RUN dotnet restore
# Copy everything and publish
COPY . .
RUN dotnet publish src/MyApp -c Release -o /app/publish
FROM mcr.microsoft.com/dotnet/aspnet:10.0-noble-chiseled AS production
WORKDIR /app
COPY --from=build /app/publish .
USER app
EXPOSE 8080
ENTRYPOINT ["dotnet", "MyApp.dll"]
Self-Contained Deployment
Bundles .NET runtime with app, enables smallest runtime-deps images:
FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build
WORKDIR /src
COPY *.csproj ./
RUN dotnet restore
COPY . .
RUN dotnet publish -c Release -o /app/publish \
--self-contained true \
-r linux-x64
FROM mcr.microsoft.com/dotnet/runtime-deps:10.0-noble-chiseled AS production
WORKDIR /app
COPY --from=build /app/publish .
USER app
EXPOSE 8080
ENTRYPOINT ["./MyApp"]
Native AOT (Fastest Startup)
Compiles to native code. Smallest image (~12 MB), fastest startup:
FROM mcr.microsoft.com/dotnet/sdk:10.0-aot AS build
WORKDIR /src
COPY *.csproj ./
RUN dotnet restore
COPY . .
RUN dotnet publish -c Release -o /app/publish
FROM mcr.microsoft.com/dotnet/runtime-deps:10.0-noble-chiseled AS production
WORKDIR /app
COPY --from=build /app/publish .
USER app
EXPOSE 8080
ENTRYPOINT ["./MyApp"]
Dedicated AOT SDK images include native compilation prerequisites:
mcr.microsoft.com/dotnet/sdk:10.0-aot(Ubuntu, also tagged10.0-noble-aot)mcr.microsoft.com/dotnet/sdk:10.0-alpine-aotmcr.microsoft.com/dotnet/sdk:10.0-azurelinux3.0-aot
Requires in .csproj:
<PropertyGroup>
<PublishAot>true</PublishAot>
</PropertyGroup>
Limitations: No runtime reflection, not all libraries compatible.
Dockerfile-less Container Publishing
.NET 10 supports publishing containers directly from the SDK—no Dockerfile required:
# Publish to local container runtime
dotnet publish --os linux --arch x64 /t:PublishContainer
# Publish directly to a registry (no Docker needed)
dotnet publish --os linux --arch x64 /t:PublishContainer \
-p ContainerRegistry=ghcr.io \
-p ContainerRepository=myorg/myapp
# Multi-architecture publishing
dotnet publish /t:PublishContainer \
-p ContainerRuntimeIdentifiers="linux-x64;linux-arm64"
Project file configuration:
<PropertyGroup>
<!-- Control image format: Docker or OCI -->
<ContainerImageFormat>OCI</ContainerImageFormat>
<!-- Customize base image -->
<ContainerBaseImage>mcr.microsoft.com/dotnet/aspnet:10.0-noble-chiseled</ContainerBaseImage>
<!-- Set image name and tag -->
<ContainerRepository>myapp</ContainerRepository>
<ContainerImageTag>1.0.0</ContainerImageTag>
</PropertyGroup>
Development Stage
Add a development stage for local dev with hot reload:
FROM mcr.microsoft.com/dotnet/sdk:10.0 AS base
WORKDIR /src
COPY *.csproj ./
RUN dotnet restore
FROM base AS development
COPY . .
ENTRYPOINT ["dotnet", "watch", "run"]
FROM base AS build
COPY . .
RUN dotnet publish -c Release -o /app/publish
FROM mcr.microsoft.com/dotnet/aspnet:10.0-noble-chiseled AS production
WORKDIR /app
COPY --from=build /app/publish .
USER app
EXPOSE 8080
ENTRYPOINT ["dotnet", "MyApp.dll"]
Build development: docker build --target development -t myapp:dev .
Cache Optimization
Use BuildKit cache mount for NuGet packages:
RUN --mount=type=cache,target=/root/.nuget/packages \
dotnet restore
SHA Pinning for Production
Pin exact image digests for reproducibility and security:
FROM mcr.microsoft.com/dotnet/sdk:10.0@sha256:abc123... AS build
To find the current digest, run:
docker pull mcr.microsoft.com/dotnet/sdk:10.0
docker inspect --format='{{index .RepoDigests 0}}' mcr.microsoft.com/dotnet/sdk:10.0
Required .dockerignore
Always create .dockerignore:
**/bin/
**/obj/
**/.vs/
**/.vscode/
**/node_modules/
**/*.user
**/*.userosscache
**/*.suo
*.md
.git
.gitignore
Dockerfile*
docker-compose*
Verification Checklist
- SDK image for build stage, runtime/aspnet for production
- .NET 8+ uses port 8080 (not 80)
- Copy .csproj files before source for cache efficiency
- Use
USER appfor non-root execution (chiseled images have this user) - Chiseled images have no shell—use exec form only, no
&&chains in final stage - Include .dockerignore to exclude build artifacts
- Match runtime identifier (
-r linux-x64) for self-contained builds - Consider SHA pinning for production reproducibility