If you’ve ever had to debug a .NET library that’s deployed via NuGet, you’ve probably hit this loop:
Change code in the library
Build
Pack
Publish (or at least produce a .nupkg)
Update the consuming app to the new version
Restore
Rebuild
Finally debug
Repeat… forever
It works, but it’s slow and it pollutes your package feed (or your local folder feed) with “debug build” versions that you’ll never want again.
There’s a faster workflow that’s great for tight iteration: replace the DLL directly inside the NuGet global packages cache (.nuget cache) and rebuild your consuming project. Done right, you can iterate in seconds without constantly re-versioning packages.
This post walks through the approach, how the .nuget cache is laid out, what to watch out for, and a couple of tips to keep it painless.
When you install a package, NuGet downloads and extracts it into a global folder called the global packages folder (often referred to as “the NuGet cache”, though NuGet has multiple caches).
By default, it lives at:
Windows: C:/Users/<you>/.nuget/packages
Linux/macOS: ~/.nuget/packages
Inside that folder, packages are stored like this:
So if you depend on Contoso.WidgetEngine version 2.3.1, you’ll likely find:
And inside there, you’ll see the lib/ folder (and maybe runtimes/, build/, etc.) exactly as shipped in the .nupkg.
That matters because your consuming project typically resolves reference assemblies from here during restore/build.
Build the library DLL locally → copy it over the DLL inside the package’s lib/<TFM>/ folder in .nuget/packages → rebuild the consuming project. This avoids:
generating a new .nupkg
changing the version
editing PackageReferences
restoring new packages every time
.nuget/packagesIn the consuming project, check the PackageReference:
You must match:
package id
version
target framework that the consuming app uses
Navigate to:
(or ~/.nuget/packages/...)
Inside, look for lib/:
Build your library project so you have an updated DLL:
bin/Debug/<tfm>/YourLibrary.dll
Replace the package’s DLL with your freshly built one:
From:
(Tip: keep a backup of the original files if you want to revert quickly)
Now rebuild the consuming project (or the full solution). In many cases you do not need to restore again—just rebuild.
If you’re using Visual Studio, a Rebuild is usually enough. From CLI:
At this point, your app is referencing the same package/version, but the actual bits on disk are your modified assembly.
Most apps will copy dependencies to bin/Debug/... at build time. If the consuming app already copied an older version earlier, you want to force it to refresh.
What helps:
Rebuild (not just Build)
deleting the consuming app’s bin/ and obj/ folders
ensuring the file timestamp changes on the replaced DLL (copying usually does)
Restore generally treats the global packages folder as immutable for that version. It won’t “fix” your manual changes unless you explicitly clear caches or force re-download.
That’s good for this workflow—but it can also surprise you later when you forget you modified it.
quick iteration while debugging package internals
validating a fix before you bother packaging it properly
investigating production behavior when the package was the culprit
sharing the debug build with teammates (their cache won’t match yours)
CI/build servers (they should stay deterministic)
long-term usage (it’s easy to forget you patched your cache)
This is a local developer productivity trick, not a distribution strategy.
When you’re done debugging, you’ll likely want to undo your local patch.
Options:
Restore the original DLL from a backup (fastest if you made one)
Delete the package version folder and restore again
Example:
delete .nuget/packages/contoso.widgetengine/2.3.1/
run dotnet restore
Clear relevant NuGet caches (more aggressive; usually not needed)
If the package provides net6.0 and net8.0 assemblies, replace the one your consumer actually uses.
Even a tiny script beats manual drag-and-drop. Common patterns:
a PowerShell script that copies the DLL to the right lib/<tfm> folder
a post-build target in the library project (use carefully)
It’s easy to forget you’ve “hot-patched” your .nuget cache and later wonder why behavior doesn’t match what’s in source control. A sticky note in the repo README or a small script named PATCH-NUGET-CACHE.ps1 can save you.
If you’re repeatedly debugging a .NET library delivered as a NuGet package, you don’t need to bump package versions for every debug build.
A fast iteration loop is:
Build the library locally (Debug)
Replace the DLL inside:
~/.nuget/packages/<id>/<version>/lib/<tfm>/
Rebuild the consuming project
Debug normally
It’s simple, effective, and dramatically faster than packaging and versioning every time—just remember to clean up when you’re done.