Files
renovate/lib/modules/manager/nuget/readme.md
Mattias Karlsson 5d9e0b82b5 fix(manager/nuget): detect MSBuild SDK updates in sqlproj files (#43831)
* fix(manager/nuget): detect MSBuild SDK updates in sqlproj files

MSBuild SDK versions in `<Sdk>`, `<Import Sdk>`, and `<Project Sdk>`
elements are exact pins, but NuGet versioning treats bare versions as
minimum ranges (`>=`). That caused dependencies such as
`0.1.19-preview` to resolve to the latest release and skip updates.

Apply hybrid versioning to all `msbuild-sdk` dependencies at extract
time: use strict `semver` when the pin is valid semver, otherwise fall
back to `semver-coerced` for non-standard NuGet version strings (e.g.
four-segment revisions). Also add `.sqlproj` to the default manager
file patterns for SSDT SQL projects.

Changes:
- Add `applyMsbuildSdkVersioning()` helper and wire it through all
  msbuild-sdk extract paths (XML, global.json, single-csharp-file)
- Extend `managerFilePatterns` to match `.sqlproj` files
- Add extract, util, index, and integration tests
- Document `.sqlproj` and MSBuild SDK extraction in nuget docs/readme

* fix(manager/nuget): use bump range strategy for msbuild-sdk deps

Replace hybrid semver versioning for MSBuild SDK pins with a default
package rule (`matchDepTypes: msbuild-sdk`, `rangeStrategy: bump`) per
review feedback. Remove `applyMsbuildSdkVersioning()` from all extract
paths and update tests accordingly. Sort nuget doc file extensions
alphabetically.
2026-07-02 05:13:47 +00:00

3.4 KiB

Use packageRules to control the behavior of the NuGet package manager.

The NuGet package manager supports these SDK-style files and formats:

  • .csproj
  • .fsproj
  • .sqlproj (SSDT SQL projects)
  • .vbproj
  • .props
  • .targets
  • global.json
  • dotnet-tools.json

MSBuild SDK dependencies are also extracted from:

  • <Sdk Name="..." Version="..." /> elements
  • <Import ... Sdk="..." Version="..." /> elements
  • <Project Sdk="name/version"> attributes
  • global.json → msbuild-sdks

.NET Core projects are supported by default.

For Renovate to work with .NET Framework projects, you need to update these files so they match the new SDK-style format:

  • .csproj
  • .fsproj
  • .vbproj
  • .props
  • .targets

You can also extract from the single code file projects (since .NET 10). But, you need to add those files manually to the managerFilePatterns as they are not supported by default.

Disabling updates for pinned versions

In NuGet, when you use versions like Version="1.2.3" then it means "1.2.3 or greater" (an open-ended minimum, with no upper bound). When you use versions like Version="[1.2.3]" then it means "exactly 1.2.3".

If you would like Renovate to disable updating of exact versions (warning: you might end up years out of date and not realize it) then here is an example configuration to achieve that:

{
  "packageRules": [
    {
      "description": "Skip pinned versions",
      "matchManagers": ["nuget"],
      "matchCurrentValue": "/^\\[[^,]+\\]$/",
      "enabled": false
    }
  ]
}

Getting updates for non-pinned (bare) versions

Per NuGet's versioning rules, a bare version such as Version="1.2.3" is an open-ended minimum (1.2.3 or greater) — so it is NuGet, not Renovate, that treats this as a range rather than a single version. The default rangeStrategy of auto resolves to replace for NuGet, and replace cannot produce an update for an open-ended minimum: every newer release already satisfies "1.2.3 or greater", so there is nothing to replace. The result is that Renovate detects no updates for these dependencies and closes any existing update PRs.

To keep receiving updates for bare versions, set rangeStrategy to bump. With bump, Renovate raises the minimum to the newest release (for example 1.2.3 to 1.5.0):

{
  "packageRules": [
    {
      "description": "Bump bare NuGet versions to the latest release",
      "matchManagers": ["nuget"],
      "rangeStrategy": "bump"
    }
  ]
}

!!! note This is a change in behavior. Earlier versions of Renovate anchored the "current version" directly to the value in your project file, so bare versions received updates under any rangeStrategy. Since Renovate 43.208.2, Renovate no longer treats a range (including a bare NuGet version) as the current version, so the rangeStrategy now decides the outcome: use bump to restore the previous update behavior.

Workload restore

Sometimes you need to run dotnet workload restore to ensure that all required workloads are installed before restoring the project. You can enable this behavior by adding dotnetWorkloadRestore to the postUpdateOptions in your Renovate configuration.

{
  "postUpdateOptions": ["dotnetWorkloadRestore"]
}