Choosing Between Fixed and Floating NuGet Versioning Strategies
Learn when to use fixed vs. floating NuGet versions to balance build reproducibility with automatic security updates in .NET projects.
29 Jul 2026, 10:31 UTC

The Determinism vs. Automation Trade-off
When managing .NET dependencies, you face a fundamental conflict: do you want your builds to be 100% reproducible, or do you want your projects to automatically receive security patches and bug fixes without manual intervention? This decision centers on whether you use Fixed Versioning or Floating Versions.
The risk of fixed versioning is "dependency rot," where critical security vulnerabilities persist because a developer forgot to bump a version number. The risk of floating versioning is the "broken build," where a package author releases a patch that introduces a regression, crashing your CI/CD pipeline without any code changes on your end.
Comparing Versioning Strategies
| Feature | Fixed Versioning (1.2.3) | Floating Versions (1.2.*) |
|---|---|---|
| Build Reproducibility | High: Same input always yields same output. | Low: Build output changes when new packages publish. |
| Maintenance Overhead | High: Manual updates required for every patch. | Low: Patches are adopted automatically on restore. |
| Risk Profile | Predictable: Changes only occur during intentional updates. | Volatile: External updates can trigger regressions. |
| Best Use Case | Production releases and regulated software. | Internal tools and rapid development phases. |
Engineering Trade-offs
The Case for Fixed Versions
Fixed versions are the industry standard for production environments. By specifying an exact version, you ensure that the binary running in your staging environment is identical to the one moving to production. This eliminates "ghost bugs"—issues that appear in one environment but not another due to a silent dependency update during the build process.
The Case for Floating Versions
Floating versions (using wildcards like *) are useful for internal shared libraries. If your team maintains five different internal packages that all depend on a common Core.Utils library, using floating versions ensures that every project picks up the latest Core.Utils patch without requiring five separate pull requests to update version strings.
Mitigating Risk with Central Package Management (CPM)
To avoid the chaos of floating versions across a large solution, use Central Package Management (CPM). CPM moves version definitions out of individual .csproj files and into a single Directory.Packages.props file. This allows you to maintain the stability of fixed versions while reducing the manual effort of updating them across dozens of projects.
Implementation and Validation
Below is an example of how to implement both strategies within a .NET project file. These configurations assume the use of .NET 6.0 or later.
Configuration Example
<!-- Example .csproj configuration -->
<ItemGroup>
<!-- Fixed Version: Guaranteed stability -->
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
<!-- Floating Version: Automatically takes latest 1.2.x patch -->
<PackageReference Include="Internal.Logging" Version="1.2.*" />
</ItemGroup>
Verifying the Resolved Version
Because floating versions are resolved at restore time, the .csproj file does not tell you what is actually being used. To verify the exact version resolved by NuGet, run the following command in your terminal at the project root:
# Run restore to resolve dependencies
dotnet restore
After the restore completes, navigate to the obj folder and open the project.assets.json file. Search for the package name to find the resolved version field. This is the only authoritative source for which version is currently linked to your build.
Practical Validation Test
- Set a dependency to a floating version (e.g.,
1.2.*). - Run
dotnet restoreand note the version inproject.assets.json. - Publish a new patch version (e.g.,
1.2.5) to your private NuGet feed. - Run
dotnet restoreagain. - Confirm that
project.assets.jsonnow reflects1.2.5without any changes to the.csproj.
Limitations and Risks
- Dependency Hell: If Package A requires
Shared.Lib 1.0.*and Package B requiresShared.Lib 2.0.*, NuGet will attempt to resolve the highest compatible version, but floating ranges can make these conflicts harder to debug in large graphs. - CI/CD Cache: Many CI pipelines cache the
objfolder or the global-packages folder. A floating version may not update until the cache is cleared, leading to inconsistent build results between local machines and the build server.
Rollback Procedure
If a floating version introduces a regression, immediately replace the wildcard with the last known stable version (e.g., change 1.2.* to 1.2.4) and commit the change. This forces the build to pin to the stable version until the regression is fixed.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.