This is a continuation of the original dotnet-outdated tool created by Jerrie Pelser.
If you already have the original dotnet-outdated tool installed you need to
run dotnet tool uninstall --global dotnet-outdated before installing this
version.
When using an IDE such as Visual Studio, it is easy to find out whether newer versions of the NuGet packages used by your project is available, by using the NuGet Package Manager. However, the .NET Core command-line tools do not provide a built-in way for you to report on outdated NuGet packages.
dotnet-outdated is a .NET Core Global tool that allows you to quickly report on any outdated NuGet packages in your .NET Core and .NET Standard projects.
- dotnet-outdated
- Overview
- Installation
- Usage
- Specifying the path
- Upgrading packages
- Working with secure feeds
- Handling pre-release versions
- Locking to the current major or minor release
- Reporting on transitive dependencies
- Failing when updates are available
- Auto-references
- Saving results to a file
- Including and excluding packages
- Only listing new version of packages older than a specified the number of days
- FAQ
Download and install the one of the currently supported .NET SDKs. Once installed, run the following command:
dotnet tool install --global dotnet-outdated-toolIf you already have a previous version of dotnet-outdated installed, you can upgrade to the latest version using the following command:
dotnet tool update --global dotnet-outdated-toolUsage: dotnet outdated [options] <Path>
Arguments:
Path The path to a .sln, .slnx, .slnf, .csproj, .fsproj or .cs file-based app, or to a directory containing a .NET Core solution/project. If none is specified, the current directory will be used.
Options:
--version Show version information.
-?|-h|--help Show help information.
-i|--include-auto-references Specifies whether to include auto-referenced packages.
-pre|--pre-release <PRERELEASE> Specifies whether to look for pre-release versions of packages. Possible values: Auto (default), Always or Never.
Allowed values are: Auto, Always, Never.
Default value is: Auto.
-vl|--version-lock <VERSION_LOCK> Specifies whether the package should be locked to the current Major or Minor version. Possible values: None (default), Major or Minor.
Allowed values are: None, Major, Minor.
Default value is: None.
-t|--transitive Specifies whether it should detect transitive dependencies.
-td|--transitive-depth <TRANSITIVE_DEPTH> Defines how many levels deep transitive dependencies should be analyzed. Integer value (default = 1)
Default value is: 1.
-u|--upgrade[:<TYPE>] Specifies whether outdated packages should be upgraded. Possible values for <TYPE> is Auto (default) or Prompt.
Allowed values are: Auto, Prompt.
-f|--fail-on-updates Specifies whether it should return a non-zero exit code when updates are found.
-inc|--include <FILTER_INCLUDE> Specifies to only look at packages where the name contains the provided string. Culture and case insensitive. If provided multiple times, a single match
is enough to include a package.
-exc|--exclude <FILTER_EXCLUDE> Specifies to only look at packages where the name does not contain the provided string. Culture and case insensitive. If provided multiple times, a single
match is enough to exclude a package.
-o|--output <OUTPUT_FILENAME> Specifies the filename for a generated report. (Use the -of|--output-format option to specify the format. JSON by default.)
-of|--output-format <OUTPUT_FILE_FORMAT> Specifies the output format for the generated report. Possible values: json (default), csv, or markdown.
Allowed values are: Json, Csv, Markdown.
Default value is: Json.
-ot|--older-than <OLDER_THAN_DAYS> Only include package versions that are older than the specified number of days.
Default value is: 0.
-n|--no-restore Add the reference without performing restore preview and compatibility check.
-r|--recursive Recursively search for all projects within the provided directory.
-fba|--include-file-based-apps Include loose file-based apps when recursively searching a directory.
-ifs|--ignore-failed-sources Treat package source failures as warnings.
-utd|--include-up-to-date Include all dependencies in the report even the ones not outdated.
-prl|--pre-release-label <PRERELEASE_LABEL> Specifies an optional label to restrict matches to when looking for pre-release versions of packages. For example, a label of 'rc.1' would only match
pre-release packages with a pre-release label that starts with that prefix.
-ncll|--nuget-cred-log-level <NU_GET_CRED_LOG_LEVEL> Specifies the minimum level of logs for NuGet Credential Service. Possible values: debug, verbose, information, warning (default), or error
Allowed values are: Debug, Verbose, Information, Minimal, Warning, Error.
Default value is: Warning.
-rt|--runtime <RUNTIME> Specifies an optional runtime identifier to be used during the restore target when projects are analyzed.
More information available on https://learn.microsoft.com/dotnet/core/rid-catalog.
-mv|--maximum-version <MAX_VERSION> The inclusive maximum package version to upgrade to. For example, a value of '8.0' would upgrade System.Text.Json 6.0.0 to the latest patch version of 8.0.x
You can run dotnet-outdated without specifying the Path argument. In this case, it will look in the current directory for a solution (.sln or .slnx) and if one is found it will analyze that solution. If no solution is found it will look for a project (.csproj or .fsproj) and if one is found it will analyze that project. If more than one solution or project is found in the current folder, dotnet-outdated will report an error.
You can also pass a directory in the Path argument, in which case the same logic described above will be used, but in the directory specified.
Lastly, you can specify the path to a solution (.sln or .slnx), project (.csproj or .fsproj), or .NET file-based app (.cs) which dotnet-outdated must analyze. File-based apps require .NET SDK 10.0.300 or later.
When --recursive --include-file-based-apps is used, dotnet-outdated also discovers loose .cs file-based apps that start with a shebang (#!). .cs files under a .csproj directory tree are ignored during recursive file-based app discovery.
File-based apps can declare NuGet packages with #:package and MSBuild SDK packages with #:sdk (for example #:sdk Cake.Sdk@6.0.0). Variable-backed versions use #:property the same way as for packages.
Versioned MSBuild project SDKs declared in a project file, as <Project Sdk="Aspire.AppHost.Sdk/13.0.0">, as <Sdk Name="Aspire.AppHost.Sdk" Version="13.0.0" /> or as <Import Project="Sdk.props" Sdk="Aspire.AppHost.Sdk" Version="13.0.0" />, are reported and upgraded like packages. SDKs inside XML comments are ignored. SDK versions pinned in global.json (msbuild-sdks) or through MSBuild properties are not supported.
dotnet-outdated can automatically attempt to upgrade any outdated packages to the latest version by passing the -u|--upgrade option. You can let dotnet-outdated prompt you for each outdated package by using the -u:prompt option.
If a package reference declares a version range with an upper bound, the latest version within that range is chosen and the upper bound is kept. For example, [6.0.13,7) is upgraded to [6.0.36, 7.0.0), and [6.0.13,7.0.0] to [7.0.0]. This also applies to ranges in Directory.Packages.props, VersionOverride and MSBuild properties such as $(MyPackageVersion). The range is rewritten in NuGet's normalized form. --maximum-version only narrows a declared range, so [6.0.0, 10.0.0) with --maximum-version 8.0 becomes [8.0.x, 10.0.0). Floating versions such as 6.* are replaced by a plain version, and transitive packages promoted with --transitive are always written as a plain version.
NuGet treats a package as compatible with a .NET target framework when one of its netstandard assets applies. The .NET runtime packages (such as Microsoft.Extensions.*) keep a netstandard asset after they drop a .NET version, but warn at build time that the new version doesn't support it, for example Microsoft.Extensions.Options 11.0.0 doesn't support net8.0 and has not been tested with it. The report still lists these updates, so you can see what moving to a supported target framework would bring. When upgrading, a target framework the new version declares unsupported keeps its version, and the others are upgraded. For example, in a project targeting net8.0 and net10.0 that references Microsoft.Extensions.Options separately for each, the net10.0 reference is upgraded to 11.0.0 and the net8.0 one keeps its version:
Upgrading package Microsoft.Extensions.Options...
Project MyProject upgraded successfully
Microsoft.Extensions.Options 11.0.0 doesn't support net8.0, so MyProject [net8.0] keeps 10.0.0. Move to a supported target framework to upgrade it.
To find out, dotnet-outdated downloads a new version that reaches the target framework only through netstandard, and looks in the MSBuild files restore would use for that framework, and in those of the dependencies it brings in for it, for the warning. A version that can't be downloaded or read is treated as supported. A reference whose version is shared with a target framework being upgraded (an unconditional PackageReference, a central PackageVersion, or a shared MSBuild property) is still upgraded and restored, and you are told so (before you're asked, with -u:prompt); declare it separately for each target framework to keep the unsupported ones on their version.
dotnet-outdated supports secure NuGet feeds, such as MyGet. It is suggested that you add these to your sources using the source command of the NuGet CLI. For secure feeds, you can do one of the following:
- Add a pre-authenticated URL.
- Specify the username and password for the feed using the
-UserNameand-Passwordoptions of thenuget sourcescommand. - Use a credential provider like the Azure Artifacts credential provider.
dotnet-outdated supports computer-level, user-level and project-level configuration files.
Using credential providers requires an environment variable DOTNET_HOST_PATH that is set to the path to the dotnet executable (e.g., /usr/local/share/dotnet/dotnet). Some versions of the .NET Core SDK do this for you at runtime, some do not. You will get an error message explaining this if the process finds it missing.
In my testing, I ran into issues on macOS where the location of the user-level configuration file was not detected correctly. If you run into problems where dotnet-outdated does not appear to pick up your feeds correctly, please add the source to a project-level configuration file.
Also, on macOS and Linux, the password needs to be stored in clear text. You can do this by passing the -StorePasswordInClearText option to the nuget sources command.
dotnet-outdated allows you to specify whether to use pre-release versions of packages or not by passing the -pre|--pre-release option.
The default value of Auto will determine whether to use pre-release versions of a package based on whether the referenced version itself is a pre-release version. If the referenced version is a pre-release version, dotnet-outdated will include newer pre-release versions of the package. If the referenced version is not a pre-release version, dotnet-outdated will ignore pre-release versions.
You can also tell dotnet-outdated to always include pre-release versions by passing the Always value for this option. Conversely, you can tell it to never include pre-release versions by passing the Never value.
dotnet-outdated allows you to lock the version to the current major or minor version by passing the -vl|--version-lock option.
The default value of None will return the absolute latest package, regardless of whether it is a major or minor version upgrade.
Passing a value of Major will only report on later packages in the current major version range. For example, if the current version for a package is 4.1.0, dotnet-outdated will only report on later packages in the 4.x version range.
Passing a value of Minor will only report on later packages in the current minor version range. For example, if the current version for a package is 4.1.0, dotnet-outdated will only report on later packages in the 4.1.x version range.
dotnet-outdated supports reporting on transitive dependencies as well. These are NuGet packages on which the NuGet packages directly referenced by your application depends. To enable reporting on transitive dependencies, you can pass the -t|--transitive option.
You can also specify how many levels deep it should analyze transitive dependencies with the -td|--transitive-depth option. You can pass an integer value for this option (the default value is 1).
Be careful with these options!. If you try and analyze dependencies too many levels deep, the analysis can take a very long time.
dotnet-outdated can be easily incorporated into your build process. You can optionally enable a non-zero return code when updates are found to make failing a build easy to configure. To enable this option you can pass the -f|--fail-on-updates option.
Before version 1.2 of dotnet-outdated, it used to include automatically referenced packages in the output. The automatically referenced packages are typically your framework packages, such as Microsoft.NETCore.App or NETStandard.Library. It does not make sense reporting on these as outdated since you should target a new framework to have these updated.
From version 1.2, if you want these packages reported, you can pass the -i|--include-auto-references option. These packages will also be denoted with the text [A] appearing in the output after the package name.
MSBuild SDKs that are resolved from NuGet, such as MSTest.Sdk or Cake.Sdk, can add package references of their own. Their versions come from the SDK, so they cannot be upgraded in the project. dotnet-outdated treats a package as auto-referenced when every reference to it is defined in a file inside a NuGet packages folder, and you upgrade it by upgrading the SDK. A package you also reference yourself, in the project or in a Directory.Build.props file, is reported as usual. This check runs for projects that declare an SDK other than Microsoft.NET.Sdk* in the project file or in a Directory.Build.props or Directory.Build.targets file in the project's directory or above. SDKs imported from other files are not detected.
You can save the results of dotnet-outdated to a file by specifying the name of an output file using the -o|--output option. By default, the results will be saved in JSON format. You can specify an alternate format using the -of|--output-format option.
You can choose to include only specific packages by using the -inc|--include option. Only packages whose name contain the specified value will be included. For example, if you only want to analyze packages containing the value "microsoft", you can use the command dotnet outdated --include microsoft. This option can be passed in multiple times: each package will be evaluated against all the filters. One single match is enough to include that package.
Conversely, you can exclude specific packages by using the -exc|--exclude option. In this case all packages will be analyzed except packages whose name contain the specified value. For example, if you want to exclude packages containing the value "microsoft", you can use the command dotnet outdated --exclude microsoft. This option can be passed in multiple times: each package will be evaluated against all filters. One single match is enough to exclude that package.
Please note that for both include and exclude, the comparison is culture and case insensitive.
There are some packages that have new updates almost on daily basis, and it might slow down development and will break all CI builds if dotnet-outdated is integrated into the CI - so the development team needs to urgently react on every single update.
This command will let the developers finish their job and update the packages on their own pace.
For failing CI builds, a proposed protocol is to have another CI build which will be scheduled weekly to inform developers of new packages, and they will react accordingly.
Also, some companies/users do not feel comfortable jumping directly on the newest versions, as they might contain some bugs, and might want to wait for some time before updating to the newest package.
dotnet-outdated can generate tab-completion scripts for its options and their values (for example -of <TAB> offers Csv, Json and Markdown) for Bash, Zsh, Fish, PowerShell and Nushell:
dotnet-outdated completions script <bash|zsh|fish|pwsh|nushell>Without a shell name, it uses the shell named in the SHELL environment variable (PowerShell on Windows).
Shell completions require the .NET 10 runtime or later. On older runtimes the tool runs without the completions command. Completion is registered for the dotnet-outdated command, which dotnet tool install --global puts on your PATH. It does not work with dotnet outdated, which the dotnet command's own completion handles. A script saved to a file lists the tool's options, so generate it again after you update the tool.
With the bash-completion package installed, which most Linux distributions include, save the script where bash-completion loads it on demand:
mkdir -p ~/.local/share/bash-completion/completions
dotnet-outdated completions script bash > ~/.local/share/bash-completion/completions/dotnet-outdatedWithout bash-completion, add this to your ~/.bashrc instead:
eval "$(dotnet-outdated completions script bash)"Save the script as _dotnet-outdated in a directory on your fpath:
mkdir -p ~/.zfunc
dotnet-outdated completions script zsh > ~/.zfunc/_dotnet-outdatedIf that directory is not already on your fpath, add it in your ~/.zshrc before compinit runs:
fpath=(~/.zfunc $fpath)
autoload -Uz compinit && compinitdotnet-outdated completions script fish > ~/.config/fish/completions/dotnet-outdated.fishAdd this line to your PowerShell profile, which is the file $PROFILE names:
dotnet-outdated completions script pwsh | Out-String | Invoke-ExpressionIt generates the script each time PowerShell starts, so it stays current after you update the tool. Don't append the script itself to your profile: it starts with using statements, which PowerShell only allows at the top of a file.
Save the script and source it from your config.nu:
mkdir ($nu.default-config-dir | path join completions)
dotnet-outdated completions script nushell | save -f ($nu.default-config-dir | path join completions dotnet-outdated.nu)# in config.nu
source ($nu.default-config-dir | path join completions dotnet-outdated.nu)The Nushell script asks dotnet-outdated for completions each time you press Tab, so it stays current after you update the tool.
dotnet-outdated includes a built-in Model Context Protocol (MCP) server. This allows AI agents (like Claude Desktop, GitHub Copilot, etc.) to interact with your .NET projects to discover, analyze, and update outdated NuGet packages.
To start the MCP server, run:
dotnet outdated mcpAdd the following to your claude_desktop_config.json:
{
"mcpServers": {
"dotnet-outdated": {
"command": "dotnet-outdated",
"args": ["mcp"]
}
}
}Add the following to your .vscode/mcp.json:
{
"mcpServers": {
"dotnet-outdated": {
"command": "dotnet-outdated",
"args": ["mcp"]
}
}
}dotnet-outdated does not make changes to .csproj files directly, except for versioned MSBuild project SDKs, which dotnet add package cannot update. Instead, it runs dotnet add package to update packages, so that command is responsible for those changes. For file-based apps that use variable-backed #:package or #:sdk directives, dotnet-outdated updates the referenced #:property value directly so the variable reference is preserved. Literal #:package and #:sdk directives are updated in the .cs source file. To track issues related to the .NET CLI command, head over to the .NET SDK repo
For version-only updates in Directory.Packages.props, dotnet-outdated preserves the original blank lines, indentation, line endings, trailing whitespace and UTF-8/UTF-16 byte order mark. If dotnet add package makes other XML changes, such as adding an entry, its output is kept as written, including its formatting. This also applies when a package has several PackageVersion entries in one file (for example per-target-framework entries under different Conditions) and only one of them is updated, so those files still lose their formatting.
Why I am getting an error about required library hostfxr.dll/libhostfxr.so/libhostfxr.dylib not found?
If you download the .NET Core CLI as a .zip/.tar.gz and extract it to a non default location, then you may encounter this error after installing and launching dotnet-outdated.
You can fix this error by setting the DOTNET_ROOT environment variable to point to the location of your .NET Core CLI installation. For more information, please refer to this blog post.

