What Is a Multi-Stage Dockerfile?
A multi-stage Dockerfile is a Docker build optimization technique that lets you use multiple FROM statements in one Dockerfile.
Each FROM starts a new build stage, and you can copy only what’s needed from one stage to another — for example:
Build your app in one stage (with SDK),
Run your app in another environment (with a lightweight runtime).
Why use it?
Reduces final image size (up to 70%)
Improves security (no compiler or build tools left)
Makes builds faster and cleaner
How It Works (Simplified Flow)
Stage 1: Use .NET SDK image → build and publish the app.
Stage 2: Use .NET Runtime image → copy the published files → run the app.
Best Example — Multi-Stage Dockerfile for .NET Core Web API
# ================================
# Stage 1: Build and Publish
# ================================
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
WORKDIR /src
# Copy csproj and restore dependencies (do this first for caching)
COPY ["MyApp/MyApp.csproj", "MyApp/"]
RUN dotnet restore "MyApp/MyApp.csproj"
# Copy everything else and build
COPY . .
WORKDIR "/src/MyApp"
RUN dotnet publish -c Release -o /app/publish /p:UseAppHost=false
# ================================
# Stage 2: Runtime (Final Image)
# ================================
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS final
WORKDIR /app
# Copy only the published output from build stage
COPY --from=build /app/publish .
# Set environment and entry point
ENV ASPNETCORE_URLS=http://+:8080
EXPOSE 8080
ENTRYPOINT ["dotnet", "MyApp.dll"]
What’s Happening Here
| Stage | Base Image | Purpose | Output |
|---|
build | mcr.microsoft.com/dotnet/sdk:8.0 | Compile, restore, publish the app | /app/publish folder |
final | mcr.microsoft.com/dotnet/aspnet:8.0 | Run the published app | Lightweight runtime image |
Result
Final image contains only your app + runtime.
No SDK, build tools, or temporary files.
Perfect for production use in Kubernetes, Azure App Service, or Azure VM.
Command Summary
# Build image
docker build -t myapp:latest .
# Run container
docker run -d -p 8080:8080 myapp
Pro Tips
Use alpine variant for smaller image:
FROM mcr.microsoft.com/dotnet/aspnet:8.0-alpine
Add .dockerignore to skip logs, .git, bin, obj.
Use BuildKit for faster caching:
DOCKER_BUILDKIT=1 docker build .
Conclusion
Multi-stage Docker builds are the gold standard for modern .NET deployments.
They make your container:
When deploying to Kubernetes or Azure, this approach ensures every image is clean, efficient, and production-ready.