Faster and Safer NuGet restore using Source Mapping and Lock files

  • Gérald Barré

Using NuGet packages is very common. Some options may help get better performance and security when restoring packages.

#Lock Files

When restoring packages, NuGet creates a dependency graph. This graph includes all declared packages and the transitive packages. This dependency graph is then used to determine which packages should be downloaded and installed. A lock file allows to store the dependency graph and reuse it when restoring package. This guarantees that the resolution always restore the same packages.

A lock file has multiple advantages:

  • Security: The lock file contains the package hash. If you download a corrupted or malicious package, NuGet can detect it and fail.
  • Deterministic restore: There are some cases where computing the dependency graph is not deterministic (different NuGet configuration, floating versions, package deleted on the server, etc.). Using a lock file allows to restore the same packages whatever the configuration.
  • Performance: You don't need to compute the dependency graph again when restoring packages
  • Reliability: When using a NuGet server with upstream support, such as Azure Artifacts or Artifactory, the server don't need to contact the upstream server to compute the dependency graph. So, if nuget.org is down, you can still restore packages if there are already in the server cache.

Note that there are some drawbacks:

  • You may get more merge conflicts because of the lock file
  • Some tools such as Dependabot doesn't update the lock file (at the time of writing)

To enable the lock file, you need to add the following line to your .csproj file:

Sample.csproj (csproj (MSBuild project file))
<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <!-- Generate the lock file -->
    <RestorePackagesWithLockFile>true</RestorePackagesWithLockFile>

    <!-- Restore the exact packages as listed in the lock file -->
    <RestoreLockedMode Condition="'$(ContinuousIntegrationBuild)' == 'true'">true</RestoreLockedMode>
  </PropertyGroup>
  <ItemGroup>
    <PackageReference Include="Meziantou.Framework" Version="3.0.25" />
  </ItemGroup>
</Project>

Additional resources:

#Package Source Mapping

If you have multiple NuGet sources to restore packages, you may want to enable package source mapping. NuGet tries to download packages from all sources in parallel and get the result from the first to answer. Package source mapping allows to specify which source should be used to restore a package.

Package Source Mapping provides the following advantages:

  • Deterministic restore / Security: If multiple servers contain the same package, it can be restored from any of them. But if the package is different on each server, you may get inconsistent restore.
  • Performance: NuGet won't waste time querying the multiple servers, so you reduce the number of network requests to restore packages.

To use Package Source Mapping, you need to create a nuget.config file at the root of the repository and adapt the configuration for each package.

nuget.config (XML)
<packageSources>
  <clear />
  <add key="nuget.org" value="https://api.nuget.org/v3/index.json" />
  <add key="mycompany.org" value="https://mycompany.org/nuget/" />
</packageSources>

<packageSourceMapping>
<!-- key must match the key in <packageSources> -->
  <packageSource key="nuget.org">
    <package pattern="*" />
  </packageSource>
  <packageSource key="mycompany.org">
    <package pattern="MyCompany.*" />
    <package pattern="MyCompanySpecificPackage" />
  </packageSource>
</packageSourceMapping>

If you are not sure which source was used to restore a package, you can check the .nupkg.metadata in the global cache as explain in this post.

Additional resources:

Do you have a question or a suggestion about this post? Contact me!

Follow me:
Enjoy this blog?Buy Me A Coffee💖 Sponsor on GitHub