NuGet

What is NuGet?

NuGet is .NET’s package manager - it’s how you add third-party libraries and tools to your projects. Think of it as the central place where .NET developers share and consume reusable code.

If you’ve used other languages, NuGet is .NET’s equivalent to:

  • npm (Node.js/JavaScript)
  • pip (Python)
  • Maven/Gradle (Java)
  • Cargo (Rust)
  • RubyGems (Ruby)

Instead of copying code or DLLs around, you simply declare “I need this library” and NuGet handles downloading it and all its dependencies.

Why Use NuGet?

1. No Reinventing the Wheel

Need to work with JSON? Parse CSV files? Connect to a database? Someone’s already built a great library for that:

dotnet add package Newtonsoft.Json
dotnet add package CsvHelper
dotnet add package Npgsql.EntityFrameworkCore.PostgreSQL

2. Dependency Management

NuGet automatically handles dependencies. If package A needs package B, NuGet installs both:

# You install Entity Framework...
dotnet add package Microsoft.EntityFrameworkCore

# ...NuGet automatically installs all its dependencies
# - Microsoft.EntityFrameworkCore.Abstractions
# - Microsoft.EntityFrameworkCore.Analyzers
# - Microsoft.Extensions.Caching.Memory
# - And several others

3. Version Control

NuGet manages package versions, making it easy to upgrade or stay on specific versions:

<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="Serilog" Version="3.1.1" />

How NuGet Works

When you add a package, two things happen:

1. Your .csproj File is Updated

<Project Sdk="Microsoft.NET.Sdk.Web">
  <PropertyGroup>
    <TargetFramework>net8.0</TargetFramework>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" />
    <PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.0" />
    <PackageReference Include="Serilog.AspNetCore" Version="8.0.0" />
  </ItemGroup>
</Project>

2. Packages are Downloaded

Packages are downloaded to a global cache on your machine (usually ~/.nuget/packages on Linux/Mac or %userprofile%\.nuget\packages on Windows). Your project references them from there.

Common NuGet Commands

Adding Packages

# Add the latest version
dotnet add package Serilog

# Add a specific version
dotnet add package Serilog --version 3.1.1

# Add a pre-release version
dotnet add package MyPackage --prerelease

Removing Packages

dotnet remove package Serilog

Updating Packages

# Update all packages
dotnet list package --outdated
dotnet add package Serilog  # Installs latest

# Or manually edit .csproj and change version number

Restoring Packages

When you clone a project, packages aren’t included. Restore them with:

dotnet restore

# Or just build/run - restore happens automatically
dotnet build
dotnet run

NuGet.org - The Package Registry

NuGet.org is the main public registry where packages are hosted. It’s like npm’s registry or Python’s PyPI.

Popular .NET API packages include:

  • Entity Framework Core - ORM for database access
  • Swashbuckle - Swagger/OpenAPI documentation
  • Serilog - Structured logging
  • AutoMapper - Object-to-object mapping
  • FluentValidation - Input validation
  • Dapper - Lightweight ORM
  • MediatR - CQRS/Mediator pattern
  • Polly - Resilience and fault handling

Practical Example - Building an API

Here’s what a typical API’s package references might look like:

<ItemGroup>
  <!-- Web Framework -->
  <PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="8.0.0" />
  
  <!-- Database -->
  <PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.0" />
  <PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="8.0.0" />
  
  <!-- Documentation -->
  <PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" />
  
  <!-- Logging -->
  <PackageReference Include="Serilog.AspNetCore" Version="8.0.0" />
  <PackageReference Include="Serilog.Sinks.Console" Version="5.0.1" />
  
  <!-- Validation -->
  <PackageReference Include="FluentValidation.AspNetCore" Version="11.3.0" />
  
  <!-- Testing (in test project) -->
  <PackageReference Include="xUnit" Version="2.6.1" />
  <PackageReference Include="Moq" Version="4.20.69" />
</ItemGroup>

Package Versions

NuGet uses semantic versioning (SemVer): Major.Minor.Patch

<!-- Exact version -->
<PackageReference Include="Serilog" Version="3.1.1" />

<!-- Minimum version -->
<PackageReference Include="Serilog" Version="3.1.1" />
<!-- This allows 3.1.1, 3.1.2, 3.2.0, but not 4.0.0 -->

<!-- Version range -->
<PackageReference Include="Serilog" Version="[3.1.1,4.0.0)" />
<!-- Allows 3.1.1 up to (but not including) 4.0.0 -->

Most of the time, you’ll just specify the version and .NET will handle updates within the same major version.

Private NuGet Feeds

Organizations often host their own private NuGet feeds for internal packages:

<!-- nuget.config -->
<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <packageSources>
    <add key="nuget.org" value="https://api.nuget.org/v3/index.json" />
    <add key="CompanyFeed" value="https://nuget.company.com/feed" />
  </packageSources>
</configuration>

Common private feed providers:

  • Azure Artifacts
  • GitHub Packages
  • MyGet
  • ProGet
  • JFrog Artifactory

Creating Your Own Package

If you build a reusable library, you can publish it as a NuGet package:

# Pack your project
dotnet pack

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

Transitive Dependencies

NuGet handles “dependencies of dependencies” automatically:

Your Project
 └─ Entity Framework Core 8.0.0
     ├─ Microsoft.EntityFrameworkCore.Abstractions 8.0.0
     ├─ Microsoft.EntityFrameworkCore.Analyzers 8.0.0
     ├─ Microsoft.Extensions.Caching.Memory 8.0.0
     │   └─ Microsoft.Extensions.DependencyInjection.Abstractions 8.0.0
     └─ Several other packages...

You only need to reference Entity Framework Core - NuGet handles the rest.

Visual Studio vs CLI

You can manage packages in two ways:

Visual Studio (GUI)

Right-click project → Manage NuGet Packages → Browse/Installed/Updates

Command Line (dotnet CLI)

dotnet add package PackageName
dotnet remove package PackageName
dotnet list package

Both do the same thing - it’s just personal preference. The CLI is more common in modern .NET development and works everywhere (Windows, Mac, Linux).

Common Packages for APIs

Here are packages you’ll frequently use when building .NET APIs:

Database

dotnet add package Microsoft.EntityFrameworkCore
dotnet add package Npgsql.EntityFrameworkCore.PostgreSQL
dotnet add package Microsoft.EntityFrameworkCore.Design

Logging

dotnet add package Serilog.AspNetCore
dotnet add package Serilog.Sinks.Console

Documentation

dotnet add package Swashbuckle.AspNetCore

Validation

dotnet add package FluentValidation.AspNetCore

Testing

dotnet add package xunit
dotnet add package Moq
dotnet add package Microsoft.AspNetCore.Mvc.Testing

Package Vulnerabilities

NuGet helps identify security issues:

# Check for vulnerable packages
dotnet list package --vulnerable

# Example output:
# The following sources were used:
#    https://api.nuget.org/v3/index.json
#
# Project `MyApi` has the following vulnerable packages
#    [net8.0]:
#    Top-level Package      Requested   Resolved   Severity   Advisory URL
#    > Newtonsoft.Json      12.0.1      12.0.1     High       https://github.com/advisories/...

Then update the vulnerable package:

dotnet add package Newtonsoft.Json

Wrap Up

NuGet is simple but essential - it’s how the .NET ecosystem shares code. Rather than building everything from scratch, you leverage thousands of well-tested libraries built by the community.

Key takeaways:

  • Use dotnet add package to add libraries
  • Packages are declared in your .csproj file
  • Dependencies are automatic - NuGet handles transitive dependencies
  • Versions matter - understand semantic versioning
  • Security counts - check for vulnerabilities regularly

The beauty of NuGet is that it “just works” - add a package, start using it. No complex configuration, no DLL hell, no manual dependency tracking. It’s one of those tools that disappears into the background, letting you focus on building your API instead of managing libraries.