Skip to main content

What is NuGet? Complete Guide to .NET Package Management

NuGet is the package manager for .NET that allows you to share and consume useful code libraries. With over 400,000 packages available, NuGet is essential for modern .NET development. This comprehensive guide covers everything you need to know about NuGet package management.

What is NuGet?

NuGet is a package management system designed specifically for the Microsoft .NET ecosystem. It provides:

  • Package Distribution: Share libraries and tools
  • Dependency Management: Automatically resolve and install dependencies
  • Versioning: Semantic versioning for compatibility
  • Package Discovery: Search and browse available packages
  • Private Feeds: Host internal packages securely

NuGet Ecosystem Components

┌─────────────────────────────────────────┐
│ Your Project │
├─────────────────────────────────────────┤
│ NuGet Packages │
├─────────────────────────────────────────┤
│ Package Sources │ ← NuGet.org, Private feeds
├─────────────────────────────────────────┤
│ NuGet Client │ ← CLI, Visual Studio, etc.
└─────────────────────────────────────────┘

Understanding NuGet Packages

What is a Package?

A NuGet package is a single ZIP file with the .nupkg extension that contains:

  • Compiled Code: DLLs and executables
  • Metadata: Package information and dependencies
  • Content Files: Configuration files, documentation
  • Build Scripts: MSBuild targets and props files

Package Structure

MyPackage.1.2.3.nupkg
├── lib/
│ ├── net6.0/
│ │ └── MyLibrary.dll
│ └── netstandard2.0/
│ └── MyLibrary.dll
├── content/
│ └── config.json
├── build/
│ └── MyPackage.targets
└── MyPackage.nuspec

Installing and Managing Packages

Using Visual Studio

  1. Package Manager UI:

    • Right-click project → Manage NuGet Packages
    • Browse, install, update, and uninstall packages
    • View package details and dependencies
  2. Package Manager Console:

    # Install package
    Install-Package Newtonsoft.Json

    # Install specific version
    Install-Package Newtonsoft.Json -Version 13.0.3

    # Update package
    Update-Package Newtonsoft.Json

    # Uninstall package
    Uninstall-Package Newtonsoft.Json

Using .NET CLI

# Install package (latest version)
dotnet add package Newtonsoft.Json

# Install specific version
dotnet add package Newtonsoft.Json --version 13.0.3

# Install prerelease package
dotnet add package Microsoft.Extensions.Hosting --prerelease

# List installed packages
dotnet list package

# Remove package
dotnet remove package Newtonsoft.Json

# Restore packages
dotnet restore

Package Reference Format

Modern .NET projects use PackageReference format in project files:

MyProject.csproj
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="Serilog.AspNetCore" Version="7.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.0" />
<PackageReference Include="AutoMapper.Extensions.Microsoft.DependencyInjection" Version="12.0.1" />
</ItemGroup>

</Project>

Essential Packages for Every Developer

# JSON serialization
dotnet add package Newtonsoft.Json
dotnet add package System.Text.Json # Built-in with .NET Core+

# Logging
dotnet add package Serilog.AspNetCore
dotnet add package Microsoft.Extensions.Logging

# HTTP client
dotnet add package Microsoft.Extensions.Http

# Configuration
dotnet add package Microsoft.Extensions.Configuration
dotnet add package Microsoft.Extensions.Configuration.Json

# Dependency injection
dotnet add package Microsoft.Extensions.DependencyInjection
dotnet add package Microsoft.Extensions.Hosting

Web Development Packages

# ASP.NET Core
dotnet add package Microsoft.AspNetCore.App # Meta-package

# Entity Framework
dotnet add package Microsoft.EntityFrameworkCore
dotnet add package Microsoft.EntityFrameworkCore.SqlServer
dotnet add package Microsoft.EntityFrameworkCore.Tools

# Authentication & Authorization
dotnet add package Microsoft.AspNetCore.Authentication.JwtBearer
dotnet add package Microsoft.AspNetCore.Identity.EntityFrameworkCore

# API Documentation
dotnet add package Swashbuckle.AspNetCore

# Validation
dotnet add package FluentValidation.AspNetCore

Testing Packages

# Unit testing frameworks
dotnet add package xunit
dotnet add package xunit.runner.visualstudio
dotnet add package Microsoft.NET.Test.Sdk

# Mocking
dotnet add package Moq
dotnet add package NSubstitute

# Assertion libraries
dotnet add package FluentAssertions
dotnet add package Shouldly

# Test data generation
dotnet add package Bogus
dotnet add package AutoFixture

Utility Packages

# Object mapping
dotnet add package AutoMapper
dotnet add package AutoMapper.Extensions.Microsoft.DependencyInjection

# Caching
dotnet add package Microsoft.Extensions.Caching.Memory
dotnet add package Microsoft.Extensions.Caching.StackExchangeRedis

# Background tasks
dotnet add package Hangfire.AspNetCore
dotnet add package Quartz.Extensions.Hosting

# Date/time handling
dotnet add package NodaTime

# Rich command-line apps
dotnet add package System.CommandLine
dotnet add package Spectre.Console

Package Versioning

Semantic Versioning (SemVer)

NuGet follows Semantic Versioning: MAJOR.MINOR.PATCH[-PRERELEASE]

  • MAJOR: Breaking changes
  • MINOR: New features (backward compatible)
  • PATCH: Bug fixes (backward compatible)
  • PRERELEASE: Alpha, beta, rc versions

Version Constraints

<!-- Exact version -->
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />

<!-- Minimum version -->
<PackageReference Include="Newtonsoft.Json" Version="13.0.0" />

<!-- Version range -->
<PackageReference Include="Newtonsoft.Json" Version="[13.0.0,14.0.0)" />

<!-- Floating version (not recommended for production) -->
<PackageReference Include="Newtonsoft.Json" Version="13.*" />

<!-- Prerelease versions -->
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0-rc.1" />

Version Range Syntax

NotationDescriptionExample
1.0Minimum version≥ 1.0
(1.0,)Exclusive minimum> 1.0
[1.0]Exact version= 1.0
(,1.0]Maximum inclusive≤ 1.0
(,1.0)Maximum exclusive< 1.0
[1.0,2.0]Range inclusive≥ 1.0 and ≤ 2.0
(1.0,2.0)Range exclusive> 1.0 and < 2.0

Dependency Management

Understanding Dependencies

When you install a package, NuGet automatically resolves and installs its dependencies:

Example: EntityFramework Dependencies
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="8.0.0" />

<!-- This automatically brings in: -->
<!-- Microsoft.EntityFrameworkCore.Relational -->
<!-- Microsoft.EntityFrameworkCore -->
<!-- Microsoft.Extensions.DependencyInjection -->
<!-- System.Data.SqlClient -->

Viewing Dependencies

# List all packages including transitive dependencies
dotnet list package --include-transitive

# Check for outdated packages
dotnet list package --outdated

# Check for vulnerable packages
dotnet list package --vulnerable

# See dependency tree
dotnet list package --include-transitive --format json

Dependency Conflicts

When multiple packages require different versions of the same dependency:

Resolving Conflicts
<Project Sdk="Microsoft.NET.Sdk">

<ItemGroup>
<!-- These packages might have conflicting dependencies -->
<PackageReference Include="PackageA" Version="1.0.0" />
<PackageReference Include="PackageB" Version="2.0.0" />

<!-- Force specific version to resolve conflicts -->
<PackageReference Include="ConflictingDependency" Version="3.0.0" />
</ItemGroup>

</Project>

Package Sources and Feeds

Default Package Source

By default, NuGet uses the official NuGet Gallery:

# List configured sources
dotnet nuget list source

# Default output:
# Registered Sources:
# 1. nuget.org [Enabled]
# https://api.nuget.org/v3/index.json

Adding Package Sources

# Add private package source
dotnet nuget add source https://my-company.pkgs.visualstudio.com/_packaging/MyFeed/nuget/v3/index.json --name MyCompanyFeed

# Add source with authentication
dotnet nuget add source https://my-private-feed.com/nuget --name PrivateFeed --username myuser --password mypass

# Add local folder as source
dotnet nuget add source C:\LocalPackages --name LocalPackages

NuGet Configuration

Configure sources in nuget.config:

nuget.config
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<packageSources>
<clear />
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" />
<add key="MyCompanyFeed" value="https://my-company.pkgs.visualstudio.com/_packaging/MyFeed/nuget/v3/index.json" />
</packageSources>

<packageSourceCredentials>
<MyCompanyFeed>
<add key="Username" value="myuser" />
<add key="ClearTextPassword" value="mypass" />
</MyCompanyFeed>
</packageSourceCredentials>
</configuration>

Creating Your Own NuGet Packages

Simple Library Package

  1. Create a Class Library:
dotnet new classlib -n MyAwesomeLibrary
cd MyAwesomeLibrary
  1. Update Project File:
MyAwesomeLibrary.csproj
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<PackageId>MyAwesome.Library</PackageId>
<Version>1.0.0</Version>
<Authors>Your Name</Authors>
<Company>Your Company</Company>
<Description>An awesome library that does amazing things</Description>
<PackageTags>utility;helper;awesome</PackageTags>
<PackageProjectUrl>https://github.com/yourusername/myawesome-library</PackageProjectUrl>
<RepositoryUrl>https://github.com/yourusername/myawesome-library</RepositoryUrl>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<PackageReadmeFile>README.md</PackageReadmeFile>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
</PropertyGroup>

<ItemGroup>
<None Include="README.md" Pack="true" PackagePath="\" />
</ItemGroup>

</Project>
  1. Write Your Library Code:
StringExtensions.cs
namespace MyAwesome.Library
{
public static class StringExtensions
{
/// <summary>
/// Reverses the characters in a string
/// </summary>
/// <param name="input">The string to reverse</param>
/// <returns>The reversed string</returns>
public static string Reverse(this string input)
{
if (string.IsNullOrEmpty(input))
return input;

char[] chars = input.ToCharArray();
Array.Reverse(chars);
return new string(chars);
}

/// <summary>
/// Checks if a string is a palindrome
/// </summary>
/// <param name="input">The string to check</param>
/// <returns>True if the string is a palindrome</returns>
public static bool IsPalindrome(this string input)
{
if (string.IsNullOrEmpty(input))
return true;

string cleaned = input.ToLowerInvariant().Replace(" ", "");
return cleaned == cleaned.Reverse();
}
}
}
  1. Create Package:
# Build and create package
dotnet pack

# Or pack with specific configuration
dotnet pack --configuration Release --output ./nupkgs

Advanced Package Configuration

Advanced Package Properties
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<!-- Multi-targeting -->
<TargetFrameworks>netstandard2.0;net6.0;net8.0</TargetFrameworks>

<!-- Package metadata -->
<PackageId>MyCompany.MyPackage</PackageId>
<Version>1.2.3</Version>
<AssemblyVersion>1.2.0.0</AssemblyVersion>
<FileVersion>1.2.3.0</FileVersion>

<!-- Package details -->
<Title>My Awesome Package</Title>
<Authors>John Doe</Authors>
<Owners>MyCompany</Owners>
<Description>A comprehensive package for awesome functionality</Description>
<Summary>Short summary of the package</Summary>
<PackageTags>utility;helper;extensions</PackageTags>
<PackageReleaseNotes>
v1.2.3:
- Added new StringExtensions
- Fixed bug in IsPalindrome method
- Performance improvements
</PackageReleaseNotes>

<!-- Links -->
<PackageProjectUrl>https://github.com/mycompany/mypackage</PackageProjectUrl>
<RepositoryUrl>https://github.com/mycompany/mypackage</RepositoryUrl>
<RepositoryType>git</RepositoryType>

<!-- Licensing -->
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<!-- Or use license file -->
<!-- <PackageLicenseFile>LICENSE.txt</PackageLicenseFile> -->

<!-- Icon and readme -->
<PackageIcon>icon.png</PackageIcon>
<PackageReadmeFile>README.md</PackageReadmeFile>

<!-- Build settings -->
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<IncludeSymbols>true</IncludeSymbols>
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
</PropertyGroup>

<ItemGroup>
<!-- Include files in package -->
<None Include="README.md" Pack="true" PackagePath="\" />
<None Include="icon.png" Pack="true" PackagePath="\" />
<None Include="LICENSE.txt" Pack="true" PackagePath="\" />
</ItemGroup>

</Project>

Publishing Packages

Publishing to NuGet.org

  1. Create Account: Register at nuget.org

  2. Get API Key: Generate API key from your account settings

  3. Publish Package:

# Publish to NuGet.org
dotnet nuget push MyPackage.1.0.0.nupkg --api-key YOUR_API_KEY --source https://api.nuget.org/v3/index.json

# Include symbols package
dotnet nuget push MyPackage.1.0.0.nupkg --api-key YOUR_API_KEY --source https://api.nuget.org/v3/index.json
dotnet nuget push MyPackage.1.0.0.snupkg --api-key YOUR_API_KEY --source https://api.nuget.org/v3/index.json

Publishing to Private Feed

# Publish to Azure DevOps feed
dotnet nuget push MyPackage.1.0.0.nupkg --api-key az --source https://pkgs.dev.azure.com/myorg/_packaging/myfeed/nuget/v3/index.json

# Publish to GitHub Packages
dotnet nuget push MyPackage.1.0.0.nupkg --api-key YOUR_GITHUB_TOKEN --source https://nuget.pkg.github.com/OWNER/index.json

Continuous Deployment

.github/workflows/publish-nuget.yml
name: Publish NuGet Package

on:
push:
tags:
- 'v*'

jobs:
publish:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v3

- name: Setup .NET
uses: actions/setup-dotnet@v3
with:
dotnet-version: 8.0.x

- name: Restore dependencies
run: dotnet restore

- name: Build
run: dotnet build --configuration Release --no-restore

- name: Test
run: dotnet test --configuration Release --no-build

- name: Pack
run: dotnet pack --configuration Release --no-build --output ./artifacts

- name: Publish to NuGet
run: dotnet nuget push ./artifacts/*.nupkg --api-key ${{ secrets.NUGET_API_KEY }} --source https://api.nuget.org/v3/index.json

Package Security and Best Practices

Security Considerations

# Check for vulnerable packages
dotnet list package --vulnerable

# Audit packages for known vulnerabilities
dotnet restore --audit

# Update vulnerable packages
dotnet add package VulnerablePackage --version SAFE_VERSION

Package Validation

Enable Package Validation
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<!-- Enable package validation -->
<EnablePackageValidation>true</EnablePackageValidation>

<!-- Generate baseline for validation -->
<PackageValidationBaselineVersion>1.0.0</PackageValidationBaselineVersion>
</PropertyGroup>

</Project>

Best Practices

  1. Versioning Strategy:

    • Follow semantic versioning
    • Use prerelease versions for testing
    • Never delete published packages
  2. Documentation:

    • Include comprehensive README
    • Provide XML documentation
    • Add usage examples
  3. Testing:

    • Test packages before publishing
    • Include unit tests in your package projects
    • Test across target frameworks
  4. Dependencies:

    • Minimize dependencies
    • Use the lowest compatible versions
    • Avoid dependencies with known vulnerabilities
Good Package Example
namespace MyCompany.Utilities
{
/// <summary>
/// Provides extension methods for string manipulation
/// </summary>
/// <example>
/// <code>
/// string text = "hello world";
/// string title = text.ToTitleCase(); // "Hello World"
/// </code>
/// </example>
public static class StringExtensions
{
/// <summary>
/// Converts a string to title case
/// </summary>
/// <param name="input">The input string</param>
/// <returns>The string in title case</returns>
/// <exception cref="ArgumentNullException">Thrown when input is null</exception>
public static string ToTitleCase(this string input)
{
if (input == null)
throw new ArgumentNullException(nameof(input));

if (string.IsNullOrEmpty(input))
return input;

return CultureInfo.CurrentCulture.TextInfo.ToTitleCase(input.ToLower());
}
}
}

NuGet in Enterprise

Private Package Feeds

Enterprise organizations often need private package feeds:

  1. Azure DevOps Artifacts
  2. GitHub Packages
  3. JFrog Artifactory
  4. Sonatype Nexus
  5. MyGet

Package Management Policies

Central Package Management
<!-- Directory.Packages.props -->
<Project>
<PropertyGroup>
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
</PropertyGroup>

<ItemGroup>
<PackageVersion Include="Newtonsoft.Json" Version="13.0.3" />
<PackageVersion Include="Microsoft.EntityFrameworkCore" Version="8.0.0" />
<PackageVersion Include="Serilog.AspNetCore" Version="7.0.0" />
</ItemGroup>
</Project>
Project using central package management
<Project Sdk="Microsoft.NET.Sdk">

<ItemGroup>
<!-- No version specified - managed centrally -->
<PackageReference Include="Newtonsoft.Json" />
<PackageReference Include="Microsoft.EntityFrameworkCore" />
</ItemGroup>

</Project>

Troubleshooting Common Issues

Package Restore Issues

# Clear all caches
dotnet nuget locals all --clear

# Restore with no cache
dotnet restore --no-cache

# Restore with detailed logging
dotnet restore --verbosity detailed

# Force re-evaluation of all dependencies
dotnet restore --force

Version Conflicts

Resolve Version Conflicts
<Project Sdk="Microsoft.NET.Sdk">

<ItemGroup>
<!-- Force specific version to resolve conflicts -->
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />

<!-- Override transitive dependency version -->
<PackageReference Include="System.Text.Json" Version="8.0.0" />
</ItemGroup>

</Project>

Authentication Issues

# Configure credentials for private feeds
dotnet nuget update source MyPrivateFeed --username myuser --password mytoken

# Use credential providers for Azure DevOps
dotnet tool install -g Azure.DevOps.Nuget.CredentialProvider

# Clear and reconfigure sources
dotnet nuget remove source MyPrivateFeed
dotnet nuget add source https://my-feed.com/nuget --name MyPrivateFeed

Summary

NuGet is the cornerstone of .NET package management, providing:

Key Benefits

  • Productivity: Reuse existing solutions instead of building from scratch
  • Quality: Leverage well-tested, community-vetted packages
  • Ecosystem: Access to hundreds of thousands of packages
  • Versioning: Reliable dependency management with semantic versioning
  • Security: Built-in vulnerability scanning and security updates

Essential Skills

  1. Package Discovery: Finding the right packages for your needs
  2. Dependency Management: Understanding and resolving dependencies
  3. Version Control: Managing package versions effectively
  4. Security: Keeping packages updated and secure
  5. Package Creation: Building and sharing your own packages

Best Practices Summary

  • Use specific versions in production
  • Regularly update packages for security
  • Minimize dependencies
  • Test packages thoroughly
  • Document your packages well
  • Follow semantic versioning

Series Completion

Congratulations! You've completed the .NET Essentials Series. You now understand:

  1. What is .NET? - The platform and ecosystem
  2. CLR Basics - How .NET executes your code
  3. C# Programming - The primary .NET language
  4. Essential Libraries - Core .NET APIs and types
  5. CLI Commands - Development workflow and tools
  6. NuGet Packages - Package management and ecosystem

Next Steps

Now that you have a solid foundation in .NET, consider exploring:

  • ASP.NET Core for web development
  • Entity Framework Core for data access
  • Blazor for interactive web UIs
  • MAUI for cross-platform applications
  • Advanced C# features like source generators
  • Microservices architecture with .NET

Ready to build amazing .NET applications? PBX Digital specializes in modern .NET development. Contact us at mp@pbxdigital.net for expert consulting, development, and training services.

Continue learning with more tutorials in our documentation or explore advanced topics in our documentation.