Tips for building Nuget packages


I’ve spent a lot of time over the past couple weeks building and consuming Nuget packages on real projects. I’ve picked up a few tips that, while not mind-blowing, should help you get beyond the simple scenarios you see in most demos.  I’ll refer to an example .nuspec from one of my projects, so you may want to keep it open in your browser.

Do not store the version number in your nuspec file

I assume you already had a build script before Nuget came. You already have a way to generate and store the version of your build output. For example, I tend to store the first three components of the version in a VERSION.txt file in my code repository. It gets manually incremented when appropriate (see semver). The fourth component is the build number generated by my continuous integration server. This information is already used to generate my AssemblyInfo.cs file, artifacts package name, etc. It doesn’t make any sense for me to repeat that information in my .nuspec file, so set the version tag to 0.0.0 (see line 5) to remind yourself that it is not used. Use the -Version option of the nuget.exe pack command to provide the actual version.

Prefer the <files> element approach to adding files to your package

Again, you already have a build script, and it likely copies all of your build output to a known location. It doesn’t make sense to copy the files around even more to build the structure required by Nuget’s “conventional folders” approach. Instead, use the <files> section of your .nuspec (see line 20) to refer to the files in your build output folder. The powerful wildcard support makes it easy to include everything you want, including source code, as suggested by the next tip…

Publish symbols packages for your Nugets

Nuget has integrated support for building and publishing symbol packages to These symbol packages will greatly enhance the debugging experience for anyone that uses your library, and since its so easy, there is no reason for you to not publish them (assuming your library is open source).

  1. Include .pdb files for the files in the package’s lib folder (see line 22)
  2. Include all of the corresponding source files in the package’s src folder. Using the filespec wildcard support, this can be one line (see line 23).
  3. Pass the -Symbols flag to the nuget.exe pack command when building your package. It will create two files: yourpackage.nupkg and yourpackage.symbols.nupkg.
  4. (optional, but recommended) Register at and associate your API key with your account.
  5. A single call to nuget.exe push yourpackage.nupkg will upload yourpackage.nupkg to and yourpackage.symbols.nupkg to

SymbolSource has good instructions on how package consumers can configure Visual Studio to use the symbol packages.

Provide multiple packages that target different usage scenarios

A single source code repository may produce many build artifacts, but if they aren’t always used together, they shouldn’t be distributed via Nuget together. Instead, create a single Nuget package that targets each scenario. A perfect example of what not to do is the NUnit. package (I don’t mean to pick on NUnit, it was probably created quickly by a volunteer just to get it out there. That’s cool, I get it. If anyone from the NUnit team wants my help fixing the packages, just contact me). When you install NUnit via Nuget, you get nunit.framework.dll, nunit.mocks.dll and pnunit.framework.dll added to your project. I would guess that 90% of users just want nunit.framework.dll. Similarly, the tools folder contains a number of executables, but I bet most people just want nunit-console.exe. I would break this up into an NUnit package (nunit.framework.dll in lib and all files needed to run nunit-console.exe in tools), an NUnit.Mocks package (nunit.mocks.dll in lib and has the NUnit package as a dependency), and an NUnit.Parallel package (all of the pnunit files with a dependency on NUnit if needed). The bottles.nuspec in my example is just one of many packages produced by the bottles source code repository.

Create core packages that work outside of Visual Studio

The powershell scripts and web.config modifications are cool, but if they are not absolutely necessary to use your library, provide a “core” package that does not include them. You can always provide a “quickstart” package with these extras, and have it depend on your core package to bring in the meat.

Automate building and publishing your packages

If you follow my previous two tips, you’ll have multiple .nuspec files to deal with. Fortunately, it is easy to add a single step to your build process to create all of your packages. I have a gist with a couple examples to get you started (feel free to fork to improve or add more examples). It should be fairly straightforward to make new scripts to publish your packages based on those examples.

I feel pretty strongly about only pushing “public CI builds” to the official Nuget feed, for traceability. This makes the publishing step a little more complex, but nothing that can’t be handled in a rake script. I’ve got an example that downloads the .nupkg files built on and then publishes them.

Create an icon for your package

The icon will show up on and in the Visual Studio Nuget dialog. Not many people do it (right now), so your packages will stand out. Let GitHub serve your icon file – just browse to the icon in your repo on GitHub, and then copy the link for the “raw” url and include it as your <iconUrl> metadata. Might as well do the same for your <licenseUrl>.

Install Nuget Package Explorer

This probably should have been the first tip, its that useful. Makes it much easier to view the contents and metadata in your local .nupkg files, and download packages from Invaluable when designing your packages. It even lets you edit your packages, though I’ve never tried that.

This entry was posted in Uncategorized. Bookmark the permalink. Follow any comments here with the RSS feed for this post.
  • If you provide images then it would be more easy to understand the steps which should follow for building Nuget packages.

  • I agree with your Blog and I will be back to check it more in the future so please keep up your work. I love your content & the way that you write. It looks like you’ve been doing this for a while now, how long have you been blogging for? 

  • Raif

    Yea a bit late here but I have a question.  Lets say I have a core library which is made up of a couple of projects, and I use this in some of my other apps.  There is one root project which consumes the rest of the projects in the core so I can create a nuget pkg for that and include for the rest of the dlls.  But what if I want the source ( symbols ) should I do as you illustrate here

    but for all the projects? Like 

    or should I create a nuget pkg for each project and have my root and the rest of them consume each others pkgs? some how the latter seems messy and the former seems hacky.
    does this make any sense?

  • lucent6408d

    hi guys, I’m new to all of NuGet and chocolatey so let me ask as question. if I choose to go with a private feed or nugget server and set up a few packages in there, like flash ver 20 and then adobe releases ver21. How do I do about updating those packages whenever a new version is released? is there a way to automate that or do I have to open the nuspec file and manually update it with the new URL to the new version?… pls help :)

  • Lucian

    How does your VERSION solution work with nuget versions like “1.0.0-alpha”? This hyphen-prefix convention is an important part of nuget, but absent from things like [AssemblyVersion].

    • Ben Lewies

      Hi @@ljw1004:disqus

      If you use GitFlow / GitHubFlow, take a look at GitVersion. You can add it as a task in your build pipeline, and it will render a SemVer compliant version number based on the branch name and tag for your build – as far as I know GitVersion is available on VSTS and TeamCity. You can also let it set your asseblyversion environment variable and subsequently use the assemblyversion environment variable in your nuspec files to set your package version metadata.

      AFAIK the default scheme it implements will apply appropriate labels for all unstable package versions, but you have the option of configuring the scheme to your liking.

      I hope this answers your question.