Below is an example Dockerfile that we recommend at Depot for building images for .NET ASP.NET Core applications.
# syntax=docker/dockerfile:1
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
WORKDIR /src
COPY src/WebApp/WebApp.csproj src/WebApp/
COPY src/WebApp.Core/WebApp.Core.csproj src/WebApp.Core/
COPY Directory.Build.props ./
COPY *.sln ./
RUN --mount=type=cache,target=/root/.nuget/packages \
--mount=type=cache,target=/root/.local/share/NuGet/v3-cache \
--mount=type=cache,target=/root/.local/share/NuGet/plugins-cache \
--mount=type=cache,target=/tmp/NuGetScratchroot \
dotnet restore
COPY src/ src/
RUN --mount=type=cache,target=/root/.nuget/packages \
--mount=type=cache,target=/root/.local/share/NuGet/v3-cache \
--mount=type=cache,target=/root/.local/share/NuGet/plugins-cache \
--mount=type=cache,target=/tmp/NuGetScratchroot \
dotnet publish "src/WebApp/WebApp.csproj" \
--no-restore \
--configuration Release \
--output /app/publish
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS runtime
RUN groupadd -g 1001 appgroup && \
useradd -u 1001 -g appgroup -m -d /app -s /bin/false appuser
WORKDIR /app
COPY --from=build --chown=appuser:appgroup /app/publish .
USER appuser
ENV DOTNET_RUNNING_IN_CONTAINER=true \
DOTNET_EnableDiagnostics=0 \
HTTP_PORT=8080 \
ASPNETCORE_ENVIRONMENT=Production
ENTRYPOINT ["dotnet", "WebApp.dll"]At a high level, here are the things we're optimizing in our Docker build for a .NET ASP.NET Core application:
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS buildFROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
WORKDIR /srcWe use the official .NET 8 SDK image for the build stage, providing all necessary tools for compilation and publishing.
COPY src/WebApp/WebApp.csproj src/WebApp/
COPY src/WebApp.Core/WebApp.Core.csproj src/WebApp.Core/
COPY Directory.Build.props ./
COPY *.sln ./
RUN --mount=type=cache,target=/root/.nuget/packages \
--mount=type=cache,target=/root/.local/share/NuGet/v3-cache \
--mount=type=cache,target=/root/.local/share/NuGet/plugins-cache \
--mount=type=cache,target=/tmp/NuGetScratchroot \
dotnet restoreWe copy only the project files and solution file first for optimal layer caching. This pattern ensures that package restoration only runs when dependencies change, not when source code changes. The cache mount persists NuGet packages between builds.
COPY src/ src/
RUN --mount=type=cache,target=/root/.nuget/packages \
--mount=type=cache,target=/root/.local/share/NuGet/v3-cache \
--mount=type=cache,target=/root/.local/share/NuGet/plugins-cache \
--mount=type=cache,target=/tmp/NuGetScratchroot \
dotnet publish "src/WebApp/WebApp.csproj" \
--no-restore \
--configuration Release \
--output /app/publishAfter copying the source code, we publish the application:
--no-restore skips restoration since we've already restored packages--configuration Release builds in release mode for production--output /app/publish specifies the output directory for the published filesFROM mcr.microsoft.com/dotnet/aspnet:8.0 AS runtimeFROM mcr.microsoft.com/dotnet/aspnet:8.0 AS runtime
RUN groupadd -g 1001 appgroup && \
useradd -u 1001 -g appgroup -m -d /app -s /bin/false appuser
WORKDIR /app
COPY --from=build --chown=appuser:appgroup /app/publish .The runtime stage uses the ASP.NET Core runtime image, which is much smaller than the SDK. We create a non-root user for security and copy only the published application files.
USER appuser
ENV DOTNET_RUNNING_IN_CONTAINER=true \
DOTNET_EnableDiagnostics=0 \
HTTP_PORT=8080 \
ASPNETCORE_ENVIRONMENT=Production
ENTRYPOINT ["dotnet", "WebApp.dll"]We configure the runtime environment:
DOTNET_RUNNING_IN_CONTAINER=true enables container-optimized settingsDOTNET_EnableDiagnostics=0 disables diagnostics for productionHTTP_PORT=8080 sets the HTTP portASPNETCORE_ENVIRONMENT=Production sets the environmentCache mounts are one of the most powerful features for optimizing Docker builds with Depot. This Dockerfile uses the following cache mount syntax:
RUN --mount=type=cache,target=/root/.nuget/packages \
--mount=type=cache,target=/root/.local/share/NuGet/v3-cache \
--mount=type=cache,target=/root/.local/share/NuGet/plugins-cache \
--mount=type=cache,target=/tmp/NuGetScratchroot \
dotnet restoretype=cache: Specifies this is a cache mount that persists across builds.
Multiple cache targets:
/root/.nuget/packages: Global NuGet package cache/root/.local/share/NuGet/v3-cache: NuGet v3 API cache/root/.local/share/NuGet/plugins-cache: NuGet plugins cache/tmp/NuGetScratchroot: Temporary extraction directoryFor more information regarding NuGet cache mounts, please visit the official Microsoft documentation.