One thing I really like about using NuGet is the fact that it creates a window of opportunities: you can use it in different ways, you can abuse it in different ways. Whether you use it, or you abuse it (read: use it in a different way than it was intended to be used), that's totally up to you. However, there are some common pitfalls I've noticed people struggling with when taking things to the next level.
NuGet is a package management system: it facilitates finding, installing, updating and removing NuGet packages. It also manages metadata such as version and dependency information to prevent missing prerequisites. Packages typically contain binaries and thus implies, in most people's heads, an added dependency when installing the package in a target project or solution. This is as basic as NuGet can get.
What you see is what you get?
Some very smart guys immediately saw an opportunity here: what if my package is adding functionality instead of a dependency? Hence scaffolding was born: really great stuff! This subtle but important tweak kills the assumption though that an installed NuGet package is an added dependency.
Conclusion #1: Installing a NuGet package does not necessarily add a software dependency to the target project/solution you're developing on.
It usually does, but do not assume it does it all the time. The importance of this first conclusion might not be obvious at first, but I hope to explain it by the end of this post, when you've read my second conclusion.
Don't automate for the sake of automation
The biggest opportunity NuGet facilitates unintended, is the fact you can get rid of those referenced binaries polluting your source control system, as I explained in an earlier post. I'm really a big fan of this approach when set up properly. The NuGetPowerTools package (adding functionality!) is a must-have if you want to make life easy. After installing it, you won't have any binary dependency to any referenced library or what-so-ever. What you will get is a few extra commands ready to be used in the NuGet Package Manager Console. David Ebbo explains its usage on his blog, but the key take-away relevant to my point here is that this tiny functionality-adding package is affecting the build process. Unlike the scaffolding packages, adding functionality to the IDE, this one is adding functionality to the build process: using MSBuild targets and the NuGet commandline, a pre-build step is added to the projects, fetching the NuGet packages from a configurable package source (or multiple sources).
Knowing all this, it's really important here that you keep in mind that some core principles didn't change... at all! Continuous integration is a proven important development practice and build automation plays a key part in it (Paul Stack's excellent series on the topic should get you started). Here's where the other pitfall comes into play. Since we've changed the build process to continuously integrate NuGet packages, people start looking even for more opportunities. It is using the NuGet commandline behind the scenes, right? And it has an update command, right? So... why don't we automatically update our packages to the latest version in our automated builds? I mean, it's safe, right? The command comes with a -Safe switch, so it must be!
Well, I'm not questioning whether it is safe or not (although you fully rely on package producers using proper versioning). I'm questioning whether you should even ask the question!
Each build of a given single version (changeset/revision) of your sources should produce the same result, always! If this is not the case, your builds are not reliable, because the state of your product has not changed. Same input produces same output.
If you allow your automated builds to change the version of the referenced packages you rely on (and these are dependencies, as they are referenced by your resulting binaries), you're effectively changing the input of the build process, resulting in a different output, without affecting the state of the product in your version control system. You are adding state to your build environment, and you loose it on every build! Your build of yesterday morning might be a different one than the one produced today, even if the entire team did not commit any changes. Maybe a new version of a package was released during the night, and got picked up by today's build?
Conclusion #2: Do not auto-update NuGet packages during automated builds for the reasons explained above.
It's a small, but subtle difference between a NuGet dependency package, and a NuGet functionality package, but the implications can reach us from 'dependency hell' (what NuGet helps us to solve) to "bug management hell" (which may occur when bugs get reported on unreliable builds).