Why Is My Coffee Cold aka Optimizing Build Performance in Visual Studio

If your Visual Studio builds are slower than a Monday morning stand-up, this expert guide dives into project structure, MSBuild tricks, NuGet bottlenecks, and parallelism to help you optimize builds, reclaim flow, and stop staring at loading bars.

Why Is My Coffee Cold aka Optimizing Build Performance in Visual Studio
Photo by Tamas Pap / Unsplash

You know the drill. You hit Build Solution (Ctrl+Shift+B), stand up to make a cup of coffee, come back… and Visual Studio is still "thinking." Not debugging. Not compiling. Just sitting there, spinning up MSBuild like it's trying to warm the server room through friction alone.

If you've ever stared into the blinking abyss of the build output window and wondered whether it's worth switching careers—this article is for you.

Let’s take a deep dive into the performance rabbit hole. Not the shallow stuff like “buy an SSD”—you’ve already done that. I’m talking project structures, parallel builds, SDK-style vs legacy formats, NuGet black holes, and that wonderful beast called Incremental Builds.


🧱 The Fundamentals: It’s All MSBuild, All the Way Down

Visual Studio's build system is powered by MSBuild—essentially a glorified XML orchestrator from 2005 that’s been through more updates than your average iPhone.

MSBuild takes your .csproj and .sln files, resolves dependencies, compiles code, runs pre/post build events, and eventually emits binaries (or complaints). The faster it can do this, the sooner you can get back to writing code—or at least pretending to.

Key factors affecting performance:

  • Project structure & number of references
  • Target framework(s)
  • NuGet package resolution
  • Disk I/O and file system watchers
  • Visual Studio extensions (yes, even that cute one with the cat)

🔍 Diagnosis Before Cure: Measuring Build Times

Before you change anything, know what’s slow.

Tools to Diagnose:

  • MSBuild Binary Logger (/bl)
    Capture detailed logs with:
msbuild YourSolution.sln /bl

  • Analyze with MSBuild Structured Log Viewer
  • Project System Tools (Visual Studio extension)
    Logs real-time solution load and build performance.
  • Diagnostic Build Output
    Turn on "Detailed" or "Diagnostic" in Tools > Options > Projects and Solutions > Build and Run.

You can't optimize what you can't measure. Trust the logs.


🧬 SDK-Style Projects: Evolution Has Benefits

SDK-style projects (used in .NET Core and .NET 5+) are not just cleaner—they're faster to load, resolve, and build.

Benefits:

  • Fewer imports and targets → faster evaluation
  • Simplified csproj structure → fewer parsing steps
  • Auto-inclusion of Compile, EmbeddedResource, etc. → no globbing delay

Legacy .csproj files (think pre-2017) are like having an old flip phone in a 5G world. Upgrade, or be left behind in the dust of incremental builds that never were.


⚙️ Parallel Builds & Multi-Core CPU Party Tricks

Visual Studio has been parallelizing builds since... well, before TikTok was a thing.

How to enable it:

  • Tools > Options > Projects and Solutions > Build and Run
  • Set maximum number of parallel project builds to match your logical cores (minus a few if you’re running VMs or Docker in the background)

Also add this in Directory.Build.props:

<Project>
  <PropertyGroup>
    <BuildInParallel>true</BuildInParallel>
  </PropertyGroup>
</Project>

🚨 Caveat: Parallel builds can trip over:

  • Cross-project dependencies
  • Shared output folders (bad practice anyway)
  • Race conditions in custom build scripts

🪝 Incremental Builds: Your Compiler's Lazy Mode

MSBuild checks timestamps to determine what needs to be rebuilt. If you touch a file unnecessarily, you might accidentally trigger a full rebuild.

Tips to keep builds incremental:

  • Avoid custom targets that “touch” outputs on every run
  • Don’t output to the same folder from multiple projects
  • Use Inputs and Outputs metadata properly in your custom tasks
  • Store .pdb and intermediate files in unique folders per configuration/platform

Enable diagnostic logs and look for entries like:

Skipping target "CoreCompile" because all output files are up-to-date.

If you never see that message—you’re paying a performance tax every time you hit Build.


📦 NuGet: The Slow Thief in the Night

If your build feels like it's waiting for a conference call with NuGet.org—you're not wrong.

Optimization Techniques:

  • Use PackageReference instead of packages.config
  • Turn on Restore on Build only when necessary
  • Enable deterministic restore in CI/CD
  • Add a local NuGet cache/server (like nuget.server, Artifactory, or GitHub Packages)

And for heaven’s sake, don’t commit packages folder into Git. That’s 2013’s problem.


🧼 Clean Architecture ≠ Clean Builds

It’s tempting to hit Rebuild when something’s weird. But if you’re rebuilding 80 projects because one model class changed, that’s not “clean”—that’s a dependency hygiene issue.

Things to try:

  • Break large monolith solutions into smaller, domain-specific solutions
  • Use project references sparingly
  • Consider NuGetizing shared libraries to decouple their build cycle

Good architecture reduces compile-time dependencies. This is the build-time manifestation of SOLID principles—especially Dependency Inversion.


🧪 CI/CD Considerations: Don’t Ship Your Laptop's Problems

In CI, the rules change. You want:

  • Repeatable builds (use dotnet build --no-restore)
  • Isolated environments (no leftover global state)
  • Binary logging to catch anomalies post-mortem
  • Caching (~/.nuget, obj, bin) where possible

Dockerized CI builds can be a huge help here. And yes, build containers are faster once warmed up, because they’re predictable and slim.


🔌 Extensions: The Silent Saboteurs

That whimsical extension that colorizes your curly braces? It might be causing delays during project load or solution reload.

Audit your extensions:

  • Use devenv /safemode to test performance without them
  • Disable anything not essential for builds

Less is more. Especially when you're juggling 200k lines of code and 40+ projects.


📁 File Watchers, Antivirus, and External Interference

Your build performance is often at the mercy of things outside Visual Studio.

Recommendations:

  • Exclude bin/, obj/, and .vs/ from real-time antivirus scanning
  • Disable aggressive file system watchers (OneDrive, Dropbox, etc.)
  • Ensure your project is on an SSD or NVMe drive
  • Avoid network-mounted drives for source code

Visual Studio is fast—if you let it be.


⛩️ Directory.Build.props and the Power of Centralization

Want to streamline settings across a solution? Use Directory.Build.props and Directory.Build.targets.

Examples:

<Project>
  <PropertyGroup>
    <LangVersion>latest</LangVersion>
    <TreatWarningsAsErrors>true</TreatWarningsAsErrors>
    <RunAnalyzersDuringBuild>false</RunAnalyzersDuringBuild>
  </PropertyGroup>
</Project>

This helps:

  • Reduce per-project duplication
  • Avoid analyzer overhead during builds
  • Enforce consistency

Think of it as your solution-wide config file—like web.config, but for grownups.


🧠 The Mental Model: Think Like a Compiler

Every optimization should stem from this question:

What would I do if I had to rebuild this solution from scratch?

Would you recompile the logging library every time? Would you refetch the same packages? Would you rebuild 40 projects when only one changed?

Probably not. MSBuild agrees—with a little guidance.


🏁 The Finish Line: Build Once, Ship Fast

Build performance isn't just about speed—it's about developer flow. Every second wasted staring at a progress bar is a second not spent solving real problems.

So invest in it. Understand it. Profile it. And for the love of debugging, stop using "Rebuild Solution" as a panic button.


🎯 TL;DR

  • Use SDK-style projects and PackageReference
  • Parallelize builds and reduce dependencies
  • Profile with MSBuild binary logs
  • Optimize incremental builds
  • Beware NuGet, antivirus, and rogue extensions
  • Use Directory.Build.props for consistency
  • Clean architecture = cleaner builds

🧩 In Conclusion...

🧘 Fast builds aren’t an accident—they’re architecture, discipline, and a touch of obsession. Build smarter, not harder.