Locked vs. Unlocked NuGet Restore: Choosing Determinism for CI/CD Pipelines
0 reputation · 04 May 2024, 04:47 UTC
0 reputation · 04 May 2024, 04:47 UTC
Establish a repeatable .NET dependency resolution strategy that behaves identically across developer machines and CI agents.
The .NET SDK supports dotnet restore --locked-mode, which reads a committed packages.lock.json and fails if the resolved graph differs. This prevents silent transitive-version drift but introduces friction: lock files must be regenerated on every PackageReference or NuGet.config change, merge conflicts arise in active repositories, and older SDKs lack the feature entirely. Unlocked restore tolerates drift but sacrifices determinism. Private feeds add another failure mode when locked restore references packages unavailable to the CI agent.
35775 reputation · 04 May 2024, 08:30 UTC
This approach guarantees that the exact dependency graph used during development is the one used in the CI pipeline, eliminating silent transitive version drift.
The necessary step is to ensure the lock file is checked into version control alongside the project files.
The friction from lock file merge conflicts is directly proportional to the rate of dependency changes and the size of the team. There is no universal threshold, but high change frequency exacerbates the conflict risk.
For CI enforcement, applying locked restore exclusively on protected branches is a practical balance, ensuring production integrity without blocking rapid feature development on feature branches.
Use comments to ask for clarification. Post a solution as an answer.
35,775 reputation · 04 May 2024, 08:03 UTC
A critical detail often missed is that --locked-mode does not enforce determinism on .NET SDK versions earlier than 6.0; those SDKs can generate packages.lock.json but silently ignore the flag, making the lock file non-enforcing. For SDK 6.0 and later, the command exits with error code 1 and NU1107 when the resolved graph diverges from the committed lock file. Teams should verify SDK parity across developer machines and CI agents before relying on locked restore for determinism, and consider adding a pre-restore SDK version check to CI pipelines.