πŸ’‘ Developer Tips / Docker Layer Caching for .NET
docker

Docker Layer Caching for .NET

November 5, 2025 β€’ 2 min read
← Back to Tips
Speed up Docker builds by properly ordering your Dockerfile commands. Learn how to leverage Docker's layer caching to avoid rebuilding everything when you change your code.

The Problem

Every time you change a line of code, Docker rebuilds everything from scratch? You're not leveraging layer caching!

⚑ Proper layer caching can reduce build times from 5+ minutes to under 30 seconds!

❌ Bad: Inefficient Layer Order

FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
WORKDIR /app

# 🚫 This copies everything first!
COPY . .
RUN dotnet restore
RUN dotnet build
RUN dotnet publish -o /app/publish

FROM mcr.microsoft.com/dotnet/aspnet:8.0
WORKDIR /app
COPY --from=build /app/publish .
ENTRYPOINT ["dotnet", "MyApp.dll"]

Problem: Any code change invalidates all layers, forcing complete rebuild including dotnet restore.

βœ… Good: Optimized Layer Caching

FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
WORKDIR /app

# βœ… Copy project files first (changes rarely)
COPY *.csproj ./
RUN dotnet restore

# βœ… Copy source code after restore (changes often)
COPY . .
RUN dotnet build -c Release --no-restore
RUN dotnet publish -c Release --no-build -o /app/publish

FROM mcr.microsoft.com/dotnet/aspnet:8.0
WORKDIR /app
COPY --from=build /app/publish .
ENTRYPOINT ["dotnet", "MyApp.dll"]

🎯 Why This Works

  • Layer 1-3: Rarely change β†’ cached most of the time
  • Layer 4: Only rebuilds when .csproj changes
  • Layer 5-6: Code changes β†’ only these layers rebuild
  • Result: NuGet packages stay cached!

πŸ”₯ Advanced: Multi-Project Solutions

FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
WORKDIR /app

# Copy solution file first
COPY *.sln ./

# Copy all project files (maintaining folder structure)
COPY src/MyApp.Api/*.csproj ./src/MyApp.Api/
COPY src/MyApp.Core/*.csproj ./src/MyApp.Core/
COPY src/MyApp.Infrastructure/*.csproj ./src/MyApp.Infrastructure/
COPY tests/MyApp.Tests/*.csproj ./tests/MyApp.Tests/

# Restore all projects
RUN dotnet restore

# Copy all source code
COPY . .

# Build and publish
RUN dotnet build -c Release --no-restore
RUN dotnet publish src/MyApp.Api -c Release --no-build -o /app/publish

FROM mcr.microsoft.com/dotnet/aspnet:8.0
WORKDIR /app
COPY --from=build /app/publish .
ENTRYPOINT ["dotnet", "MyApp.Api.dll"]

πŸ’‘ Pro Tips for Maximum Speed

1. Use .dockerignore

# .dockerignore
**/bin/
**/obj/
**/.vs/
**/node_modules/
.git/
README.md
.dockerignore
Dockerfile

2. Separate NuGet Cache Layer

# For solutions with global.json or Directory.Packages.props
COPY global.json ./
COPY Directory.Packages.props ./
COPY *.csproj ./
RUN dotnet restore

3. Use --no-restore and --no-build Flags

Always use these flags to prevent unnecessary work:

  • --no-restore in build (already restored)
  • --no-build in publish (already built)

Build Time Comparison

❌ Without Layer Caching

  • First build: 5-8 minutes
  • Code change: 5-8 minutes
  • Package update: 5-8 minutes

Every change = full rebuild!

βœ… With Layer Caching

  • First build: 5-8 minutes
  • Code change: 20-60 seconds
  • Package update: 2-3 minutes

Dramatic time savings!

πŸš€ Quick Wins

  1. Copy .csproj files first β†’ cache NuGet restore
  2. Copy source code last β†’ only rebuild when code changes
  3. Use multi-stage builds β†’ smaller production images
  4. Add .dockerignore β†’ faster context copying

πŸ’¬ Comments & Reactions