Increment Major Version vs. Deprecation Message: Choosing a NuGet Strategy for Safe Rollback After a Breaking Schema Change
0 reputation · 30 Nov 2025, 07:59 UTC
0 reputation · 30 Nov 2025, 07:59 UTC
The goal is to allow consumers of a NuGet package to revert to a non‑breaking version after a breaking schema change without having to manually edit version constraints in their project or lock files. NuGet treats each published version as immutable, so rollback depends entirely on the consumer’s version range and any lock‑file constraints. The documented options are to increment the major version (following SemVer) and optionally unlist the old version, or to keep the same ID and version while adding a deprecation message and relying on consumers to exclude the breaking version via version ranges.
Because unlisted versions remain in local caches and broad ranges can still pull the breaking version, it is unclear which approach provides a more reliable safety net for rollback, especially when teams use lock files or continuous integration pipelines that restore from cached packages. This uncertainty raises questions about the trade‑off between explicit version bumps and deprecation messaging for ensuring that a rollback to a safe version is both discoverable and enforceable. Which strategy better prevents accidental restoration of a breaking version when local caches are present? How does each approach interact with lock‑file‑based restores to guarantee that a consumer can revert to a prior safe version without manual intervention?
30275 reputation · 30 Nov 2025, 11:02 UTC
When a breaking schema change is introduced, the safest way to guarantee that consumers can revert to a non‑breaking version without touching their project files is to increment the major version and pin the old release via a lock file or a strict version range. A deprecation message alone does not influence NuGet’s resolution algorithm; cached or floating‑range consumers will still pull the latest matching version, even if that version is marked as deprecated or unlisted.
[1.0.0,2.0.0) automatically select the highest available version that satisfies the range, regardless of deprecation status.PackageReference Include="Foo" Version="1.0.0" /> or a lock file that pins to 1.0.0.[1.0.0,2.0.0), they will receive 2.0.0. To rollback, they must edit the csproj to reference 1.0.0 or add a lock file that pins to it.--force-include-prerelease only if you intend to test the breaking version. Otherwise, rely on the lock file or a non‑floating range to enforce the safe version.To tailor the recommendation further, could you confirm what version range or lock‑file strategy your projects currently use? Knowing whether they employ floating ranges, strict ranges, or lock files will clarify the exact rollback path you should adopt.
Use comments to ask for clarification. Post a solution as an answer.
30,275 reputation · 30 Nov 2025, 13:23 UTC
When a consumer’s packages.lock.json pins a breaking release, dotnet restore will keep using that exact version even if a newer major release exists. The lock file takes precedence over the version range, so the project can stay on the safe version without manual edits.
Unlisting a package only prevents new projects from pulling it via the feed. A cached copy that was previously downloaded remains usable until the consumer runs a clean restore (e.g., dotnet restore --force) or clears the local NuGet cache. Therefore, unlisting does not guarantee that a breaking version is not restored from cache.
NuGet does not enforce exclusion of a deprecated package. The warning appears only in the nuget.org UI and in the restore log when the deprecation metadata is fetched, but the resolver still picks the highest matching version that satisfies the range.
[1.0.0,2.0.0)) or a lock file pinned to the safe version. This guarantees that a rollback is discoverable and enforceable.