NuGet is now fully integrated into MSBuild

In the past, NuGet packages were managed in two different ways - packages.config and project.json - each with their own sets of advantages and limitations. With Visual Studio 2017, we have revamped the NuGet package management experience by introducing PackageReference. PackageReference brings new and improved features such as deep MSBuild integration, improved performance for everyday tasks such as install and restore, multi-targeting and more.

Try out PackageReference today!

To get a piece of the PackageReference goodness, download Visual Studio 2017 and create a .NET Standard class library or any .NET Core project. These projects come with PackageReference by default. You can also try PackageReference with other project types .

Do install your favorite NuGet packages, try out different scenarios and workflows, and if you run into an issue or find something broken, open an issue on GitHub.

PackageReference – the one NuGet format to rule them all

Manage all project dependencies in one place

Just like project to project references or assembly references, you can now view and manage NuGet package references from the MSBuild project file (e.g. csproj).


See only those dependencies you care about

In the past, if your project referenced package A, which in-turn referenced packages B, C and D, you would see all of them listed as your dependencies. With Transitive Package Restore, NuGet dynamically resolves the down-level dependencies giving you an uncluttered view of the dependencies you care about. Additionally, project files are not modified on restore, avoiding merge conflicts and file churn on commits. This also allows the project system to evolve independent of NuGet.

Performance improvements

Package installs/updates are now at least 5x faster. With PackageReference and Transitive Package Restore, we no longer stamp every down-level dependency into the project file. For a sample scenario with 5 targets each having 20-30 deep dependency chains, update/install used to take ~10 mins to complete, now takes ~30ms.

No more solution-local packages folders – Packages are now resolved against the user’s cache, rather than a solution specific packages folder. This makes PackageReference perform faster and consume less disk space.

Fine control over dependencies and content flow

  • Harnessing the power of MSBuild, you can conditionally reference a NuGet package. This allows you to use MSBuild conditions to choose package references per target framework, configuration, platform, or other pivots. For example:

      <PackageReference Include="NuGet.Versioning" Version="3.6.0" Condition = "'$(TargetFramework)' == 'netstandard10'"/>
  • You might be using a dependency purely as a development harness and might not want to expose that to projects that will consume your package. In this scenario, you can use the PrivateAssets metadata to control this behavior. For example:

      <PackageReference Include="Contoso.Utility.UsefulStuff" Version="3.6.0">
  • You can control the flow of dependency assets using Include/Exclude Assets metadata. In the following example, everything except the content files from the package would be consumed by the project and everything except content files and analyzers would flow to the parent project.

      <PackageReference Include="Contoso.Utility.UsefulStuff" Version="3.6.0">
  • You now have flexibilty to express dependency versions using either version ranges or floating versions. In the first example, using version range, you can restrict the package version range which NuGet accepts to 1.3.2 up to 1.4.x, but not 1.5 and higher. In the second example, using floating version, NuGet will always bring the latest version of the ExamplePackage that matches the pattern 1.4.x.

      <PackageReference Include="ExamplePackage" version="[1.3.2,1.5)" />
      <PackageReference Include ="ExamplePackage" version="1.4.*"/>

Define nuspec Metadata in project files

You can now author NuGet packages by specifying NuGet properties in your project file. You can also define these properties from the project properties. Additionally, you can choose to auto-generate a NuGet package on every build by checking the “Generate NuGet package on build” property.


Build packages directly from a project

With pack and restore as msbuild targets, NuGet is now a first class MSBuild citizen. For example, you can do msbuild /t:pack in a project directory which would generate a NuGet package using the properties and metadata declared in the project file. Additionally, in a CI/CD scenario, NuGet error and warnings are collated with the MSBuild output, giving you a single view of your build output.

Background Package Restore

In the past, you had to perform a build or an explicit restore to restore NuGet packages. With NuGet 4.0, background package restore automatically downloads and adds or removes NuGet packages as you edit PackageReference and save your project files.

Package project duality

As a package author, you can now expect the exact same behavior when referencing a library either as a Project to Project reference or as NuGet package. This streamlines your inner loop when authoring NuGet packages as you no longer need to go through the change-build-pack-restore loop to test a change.

Develop against multiple TFMs

You can now specify multiple TFMs and at pack time, NuGet will do the right thing to create a nupkg with the correct package structure. For example:


What about other project types that are not .NET Core?

You can get a first look of what will come in the next NuGet update. Hop on to the Visual Studio 2017 Update 1 Preview 2 bandwagon. Once you have the VS 2017 U1 Preview 2, you can try PackageReference with any packages.config based project. Navigate to Tools > Options> NuGet Package Manager > General and check the “Allow format selection on first package install” option.


Create a new packages.config based project and attempt to install a NuGet package. You will be prompted by the dialog below. Select the PackageReference option and hit ok.


Some of the features discussed earlier are not yet fully supported for packages.config based projects such as defining nuspec metadata in project files, building packages directly from a project, background package restore, developing against multiple TFMs, and package project duality. We are hard at work to bring full PackageReference support to these project types. Our goal is to eventually make PackageReference the default and move away from all other formats.

Will existing NuGet package management formats continue to work?

PackageReference is only supported in Visual Studio 2017. However, we remain fully committed to maintaining compatibility of existing projects created with Visual Studio 2015. In Visual Studio 2017 while we will provide newer experiences that will help you migrate your projects to use the new PackageReference format and will offer you options to make PackageReference the default format for newly created projects, we will continue to emphasize the ability of Visual Studio 2015 and Visual Studio 2017 to round-trip projects as much as possible.

Will existing NuGet packages work if I am using PackageReference for WPF, Windows Forms or ASP.NET projects?

While we have done a lot of work to ensure that existing packages on just work with the PackageReference format, there are a few scenarios that will not be supported in the PackageReference world and might impact your ability to migrate away from packages.config. Some examples of scenarios that will not be supported include content folders (we have introduced ContentFiles), XDT transforms, PowerShell scripts i.e. install.ps1 and uninstall.ps1 (only init.ps1 is supported) . If you come across a package you consume in your WPF or Windows Forms app that worked previously but does not work on migrating your project to PackageReference, we would love to hear from you, so that we can investigate what the incompatibilities might be.

We want to hear your feedback!

We want NuGet to meet the evolving needs of our community. If you would like to share your pain points, and your current or future needs, hit us up at You can also leave a comment below, and as always, if you run into any issues or have an idea, open an issue on GitHub.

Published March 16, 2017 by Karan Nandwani

Announcing NuGet 4.0 RTM

Visual Studio 2017 comes with NuGet 4.0 which adds support for .NET Core, has a bunch of quality fixes and improves performance. This release also brings several improvements like support for PackageReference, NuGet commands as MSBuild targets, background package restores, and more.


Visual Studio 2017 RTM is available for download here. The NuGet Package Manager extension is already built-in, so you do not have to install or update it.

NuGet.exe 4.0 is also available for download as a separate component, here.

NuGet Package Manager Extension in Visual Studio 2017

Starting with NuGet 4.0 in Visual Studio 2017, the NuGet Package Manager will be shipped as a part of Visual Studio, and newer versions will not be available for download from the VS extensions gallery. NuGet updates will be pulled in automatically along with other Visual Studio updates.

The NuGet 4.0 Package Manager Extension is currently not available for Visual Studio 2015 (Visual Studio 2015 comes with NuGet 3.4.4, and NuGet 3.5.0 is available as an explicit download for Visual Studio 2015 as well). NuGet 4.0 builds upon several new features and bug fixes available only in Visual Studio 2017, and hence the newer NuGet experiences will not be available in Visual Studio 2015. At the same time, we want packages to work seamlessly across Visual Studio versions. We will be monitoring feedback to determine what experiences we want to enable in Visual Studio 2015 in a future release (for example, the introduction of newer TFMs).

New Features


PackageReference will become the standard way to manage NuGet dependencies across all project types. With NuGet 4.0, PackageReference is fully supported for .NET Core projects. This allows you to use MSBuild conditions to choose package references per target framework, configuration, platform, or other pivots. It also allows for fine-grained control over dependencies and content flow. Here is an example of how you would add a PackageReference in your MSBuild-based project file:

    <PackageReference Include="Contoso.Utility.UsefulStuff" Version="3.6.0"/>

You can also try PackageReference with other project types such as WinForms, Windows Presentation Foundation(WPF), and Universal Windows Platform (UWP). More details about usage and known limitations of using PackageReference in non-.NET Core projects will be available on this blog soon.

First class MSBuild citizen

In the past, it was a little tricky to make NuGet work with MSBuild. In this release, we are shipping Restore and Pack as first class MSBuild targets. This will allow you to easily work with NuGet as you would with any task or target in MSBuild. You can now produce packages directly from a project. For example, you can do msbuild /t:pack in a project directory which would generate a NuGet package using the properties and metadata declared in the csproj file of the project.

In CI systems, you no longer need to download nuget.exe and run nuget restore to restore packages. You can now use msbuild /t:restore to restore packages.

Background Package Restore

In the past, you had to perform a build or an explicit restore to restore NuGet packages. With NuGet 4.0, background package restore automatically downloads and adds or removes NuGet packages as you edit PackageReference and save your project files.

New commands in the .NET CLI

We have added new commands for the .NET CLI - dotnet nuget locals, dotnet nuget push, and dotnet nuget delete. dotnet nuget locals allows you to manipulate and work with the nuget caches on your machine. dotnet nuget push / delete – enables pushing packages to or deleting packages from NuGet servers. Additionally, dotnet restore and dotnet pack now have the same behavior as MSBuild restore and MSBuild pack providing a consistent and reliable experience.

dotnet restore == msbuild /t:restore
dotnet pack == msbuild /t:pack  

Performance Improvements

The following are some performance improvements that you might notice with NuGet 4.0:

nuget update for UWP, WPF and other project.json based projects is now much faster. In our sample solution with 20 UWP projects, updating packages is 6 times faster than before. For packages.config based projects, nuget update is now about 20% faster.

nuget restore for UWP, WPF and other project.json based projects has been improved. In one of our sample projects, restore times have been reduced from about 3800ms to about 400ms.

nuget update/install for packages that have deep dependencies is now faster by an order of magnitude. For a sample scenario with 5 targets each having 20-30 deep dependency chains, nuget update/install used to take about 10 mins to complete, compared to about 30ms now.

In .NET Core, tool restores have been optimized so that tool references are restored only once per solution instead of once for every project.

Breaking Changes

Default Location for the machine-wide NuGet.config

In Visual Studio 2017 and above, the machine-wide NuGet.config is located at %ProgramFiles(x86)%\NuGet\Config\. Going forward, nuget.exe v4.0.0+ will also treat this as the new location for the machine-wide configuration. The primary driver for the change is to improve security in a multi-user scenario. Previously we would write to the %ProgramData% folders which don’t require Admin privileges to modify. %ProgramFiles(x86)% folders are protected and only users with Administrative privileges, or those granted permissions by an administrator can change their contents.

Impact - NuGet.config in %ProgramData%\NuGet\Config\ will no longer be implicitly referenced or considered for hierarchical merging of NuGet.config. This is only applicable if you were previously using machine-wide NuGet configuration files. Solution - You must manually migrate existing config files from %ProgramData% to %ProgramFiles(x86)%

Release Notes

4.0 release notes

We want to hear your feedback!

We want NuGet to meet the evolving needs of our community. If you would like to share your pain points, and your current or future needs, hit us up at You can also leave a comment below, and as always, if you run into any issues or have an idea, open an issue on GitHub.

Published March 08, 2017 by Anand Gaurav

Introducing scoped API keys

Update 2/14 (05:00 PM PST): This feature is now live! Login to your nuget account and expand the API Keys section to see the new experience.

Since last year, we have been working on several fronts to advance NuGet as a secure environment for package distribution. This post describes an experience that will allow you to have better control of API keys that you use to push packages. Please note that this experience is currently only available on our staging environment and will be deployed to once we have incorporated your feedback, as described below.

Feature summary

This feature will give you better control on your APIs as you can now:

We would love for you to try this feature and give us feedback!

Go to to try the feature. Since this is a staging environment, you might have to create a new account and push new packages to try out the feature. Also, to set API key and then to push packages, you have to use -Source option as specified below:

nuget.exe setApiKey [your API key] -Source
nuget.exe push MyPackage.1.0.nupkg -Source

Share your feedback with us via comments in the blog, filing a Github issue or sending an email to our team.

Why introduce the concept of scoped API keys?

We made some changes to API keys last year. We want to further that experience with the introduction of the concept of scopes for API keys that will allow you to have more fine-grained permissions. Today, NuGet offers a single API key for an account, and that approach has several drawbacks:

  • One API key to control all packages: With a single API key that is used to manage all packages, it becomes really difficult to securely share the key when multiple developers are involved with different packages, and share a publisher account. An example of an account where we see a lot of pain on this front is our own Microsoft account that we use to push hundreds of packages across many teams.
  • All permissions or none: Anyone with access to the API key has all permissions (publish, push and un-list) on the packages. This is often not desirable in a multiple developer/team environment.
  • Single point of failure: A single API key also means a single point of failure. If the key is compromised, all packages associated with the account could potentially be compromised. Refreshing the API key is the only way to plug the leak which results in an interruption to your CI/CD workflow. In addition, there may be cases when you want to revoke access to the API key for an individual (for example, when an employee leaves the organization). There isn’t a clean way to handle this today.

With scoped API keys, we have tried to address the problems stated above and at the same time, we have made sure that none of the existing workflows will break.

Create scoped API keys

You can now create multiple API keys based on your requirements. An API key can apply to one or more packages, have varying scopes that grant specific privileges, and have an expiration date associated with it.


In the screenshot above, you can have an API key named ‘Contoso service CI’ that can be used to push packages for certain ‘Contoso.Service’ packages, and is valid for 365 days. This is a typical scenario where different teams within the same organization work on different packages and the members of the team are provided the key which grants them privileges only on the package they are working on. The expiration serves as a mechanism to prevent stale or forgotten keys.

Using glob patterns

If you are working on multiple packages and have a large list of packages to manage, you may choose to use globbing patterns to select multiple packages together. For example, if you wish to grant some key certain scopes on all packages whose ID starts with Fabrikam.Service, you could do so by specifying “fabrikam.service.*” in the Glob pattern text box.

Glob patterns

Using glob patterns to determine API key permissions will also apply to new packages matching the glob pattern. For example, if you try to push a new package named ‘Fabrikam.Service.Framework’, you can do so with the key you would have created in the above step, since the package matches the glob pattern “fabrikam.service*”

Obtain API keys securely

For security, a newly created key is never shown on the screen and is only available with the copy button. Similarly, it will not be accessible again after the page is refreshed.

Obtain API keys

Edit existing API keys

Another use case is being able to update the key permissions and scopes without changing the key itself. If you have a key with specific scope(s) for a single package, you may choose to apply the same scope(s) on one or many other packages.

Edit API keys

Refresh or delete existing API keys

The account owner can choose to refresh the key, in which case the permission (on packages), scope and expiry remain the same but a new key is issued making the old key unusable. This is helpful in dealing with stale keys or where there is any potential of an API key leakage.

Refresh API keys

You can also choose to delete these keys if they are not needed anymore. Deletion will remove the key and make it unusable.


What happens to my old (legacy) API key?

Your old API key (legacy) continues to work and can work as long as you want it to work. However, as was the case before, these keys will be retired if they have not been used for more than 365 days to push a package. Refer to the blog post changes expiring to API keys for more details. You can no longer refresh this key. You need to delete the legacy key and create a new scoped key, instead.

Note: This key has all permissions on all the packages and it never expires. You should consider deleting this key and creating new keys with scoped permissions and definite expiry.

How many API keys can I create?

There is no limit on the number of API keys you can create. However, we advise you to keep it to a manageable count so that you do not end up having many stale keys with no knowledge of where and who is using them.

Can I delete my legacy API key or discontinue using now?

Yes. You can, and you probably should. We recommend you delete the legacy API key and start using the new key(s) as soon as we move this feature into our production service (this feature is currently only present in our staging environment).

Can I get back my API key that I deleted by mistake?

No. Once deleted, you can only create new keys. There is no recovery possible for accidently deleted keys.

Does the old API key continue to work upon API key refresh?

No. Once you refresh a key, a new key gets generated that has the same scope, permission and expiry as the old one. The old key ceases to exist.

Can I give more permissions to an existing API key?

You cannot modify the scope but you can edit the package list it is applicable to.

How do I know if any of my keys expired or getting expired?

If any key expires, we will let you know through a warning message at the top of the page. We also send a warning e-mail to the account holder 10 days before the expiration of the key so that you can act on it well in advance.

Expired keys

Next steps

We would love to hear your feedback. Keep them flowing via comments in the blog, filing a Github issue or by sending an email to our team. Once we address the feedback, we would like to go live with this feature - preferably in a couple of weeks from today.

Published February 02, 2017 by Anand Gaurav

Older Posts

January 19, 2017 NuGet - Ending Windows XP support
January 12, 2017 Improving the NuGet documentation experience on
December 21, 2016 NuGet.Server 2.11.3 now available
November 21, 2016 Announcing NuGet 4.0 RC
October 27, 2016 Announcing NuGet 3.5 RTM
September 20, 2016 New experience for NuGet Documentation
August 25, 2016 Changes to Expiring API Keys
August 22, 2016 The path towards better documentation
August 11, 2016 Announcing NuGet 3.5 RC
June 27, 2016 Announcing NuGet 3.5 Beta 2 and 2.12 RTM