/flags/nuget/dotnet-restore-locked-mode
dotnet restore --locked-mode: fail when packages.lock.json does not match
- tool
- NuGet
- command
- dotnet restore
- flag
- --locked-mode, --use-lock-file, --force-evaluate
- default
- off (the lock file is updated when references change)
NuGet can record the exact resolved version of every direct and transitive package in packages.lock.json. dotnet restore --locked-mode restores only what that file says and fails with NU1004 if the project's package references no longer match it, instead of rewriting the file. Use it in CI so a build cannot silently resolve different versions than the ones committed. The lock file must be enabled first with RestorePackagesWithLockFile (or --use-lock-file).
Changed reference, locked restore
dotnet new classlib -o Lib > /dev/null && cd Lib
dotnet add package Newtonsoft.Json --version 13.0.3 > /dev/null
dotnet restore --use-lock-file -v q > /dev/null
ls packages.lock.json
sed -i 's/Version="13.0.3"/Version="13.0.1"/' Lib.csproj
echo "--- dotnet restore --locked-mode"
dotnet restore --locked-mode 2>&1 | grep -o "error NU1004: .*" | sed -E 's/ \[[^]]*\]$//' | head -1
echo "--- dotnet restore (updates the lock file)"
dotnet restore -v q > /dev/null; echo "exit: $?"
grep -A4 '"Newtonsoft.Json"' packages.lock.json | grep resolved
dotnet restore --locked-mode -v q > /dev/null; echo "locked again, exit: $?"Output
packages.lock.json
--- dotnet restore --locked-mode
error NU1004: The package reference Newtonsoft.Json version has changed from [13.0.3, ) to [13.0.1, ).The packages lock file is inconsistent with the project dependencies so restore can't be run in locked mode. Disable the RestoreLockedMode MSBuild property or pass an explicit --force-evaluate option to run restore to update the lock file.
--- dotnet restore (updates the lock file)
exit: 0
"resolved": "13.0.1",
locked again, exit: 0After the version in the project file changed, locked mode refuses to restore and explains which references differ. A normal restore rewrites packages.lock.json, and locked mode passes again.
Options and properties
| Option or property | Effect |
|---|---|
| --use-lock-file | Create or update packages.lock.json for this restore |
| RestorePackagesWithLockFile=true | Same, permanently in the project |
| --locked-mode | Fail with NU1004 instead of updating the lock file |
| RestoreLockedMode=true | Locked mode from MSBuild (for example only in CI) |
| --force-evaluate | Re-resolve all dependencies even if the lock file is valid |
| --lock-file-path PATH | Use a lock file in another location |
dotnet build and dotnet test restore implicitly and accept the same options (dotnet build --locked-mode), or use --no-restore after an explicit locked restore.
CI setup
dotnet restore --locked-mode
dotnet build --no-restore -c Release
dotnet test --no-build -c ReleaseWith central package management (Directory.Packages.props) each project still has its own packages.lock.json; changing a central version invalidates every lock file that uses the package.
Pitfalls
- A lock file generated for one set of runtime identifiers fails on another; include every RID you restore for in
RuntimeIdentifiers. - Different SDK versions may write different lock files for the same project. Pin the SDK with
global.json. NU1004can also appear when a project reference adds packages; restore the whole solution and commit every changedpackages.lock.json.- Downgrades are still reported separately as NU1605; other codes are listed in NuGet error codes.
FAQ
How do I create packages.lock.json?
Set <RestorePackagesWithLockFile>true</RestorePackagesWithLockFile> in the project (or Directory.Build.props) and run dotnet restore once. Commit the generated packages.lock.json next to the project file.
How do I update the lock file after changing a package version?
Run dotnet restore without --locked-mode; NuGet rewrites packages.lock.json to match. If the file still keeps an old resolution, run dotnet restore --force-evaluate.
Can I turn on locked mode only in CI?
Yes. Pass --locked-mode in the pipeline, or set <RestoreLockedMode Condition="'$(CI)' == 'true'">true</RestoreLockedMode> in the project so local restores can still update the file.