100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace
C#

NuGet Packages

Understand NuGet, the .NET package manager, and how to add, version, and manage dependencies via PackageReference in modern .NET projects.

.NET Ecosystem & TestingBeginner7 min readJul 9, 2026
Analogies

NuGet Packages

NuGet is the standard package manager for .NET, providing a way to discover, install, update, and share reusable libraries as versioned packages (.nupkg files) rather than manually copying DLLs between projects. A NuGet package bundles compiled assemblies (potentially for multiple target frameworks), metadata (author, license, dependencies), and sometimes build-time assets or analyzers. The public nuget.org registry hosts hundreds of thousands of packages, from foundational libraries like Newtonsoft.Json to entire frameworks like Entity Framework Core, and organizations commonly run private feeds (Azure Artifacts, GitHub Packages) for internal packages.

🏏

Cricket analogy: NuGet is like a cricket equipment supplier catalog where you order a specific bat model with maker's specs attached, rather than borrowing a random bat from a teammate's kit bag; big clubs also run private supplier deals alongside the public sports store.

PackageReference and the modern .csproj format

Modern SDK-style .csproj files declare dependencies with <PackageReference> elements specifying a package ID and version, replacing the older packages.config file and the even older approach of committing binaries directly to source control. Restoring packages (dotnet restore, which also runs implicitly before build) downloads the declared packages and their transitive dependencies into a local cache (~/.nuget/packages) and resolves the full dependency graph, including version conflicts between transitive dependencies via NuGet's nearest-wins and lowest-applicable-version resolution rules.

🏏

Cricket analogy: Listing required equipment in a squad's official kit list replaces the old habit of physically stockpiling gear in a shed; 'restoring' is like the kit manager fetching everything listed plus required accessories from a central warehouse before match day, resolving conflicting bat-size requests via seniority rules.

csharp
<!-- OrderService.csproj  SDK-style project file -->
<Project Sdk="Microsoft.NET.Sdk">

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

  <ItemGroup>
    <PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="8.0.4" />
    <PackageReference Include="FluentValidation" Version="11.9.0" />
    <PackageReference Include="Serilog.AspNetCore" Version="8.0.1" />
  </ItemGroup>

</Project>

Adding a package via the CLI (dotnet add package Serilog.AspNetCore) or via the Visual Studio/Rider NuGet UI edits this same PackageReference list — there's no hidden magic beyond that XML entry plus the restore step that fetches and caches the actual binaries.

🏏

Cricket analogy: Whether the coach requests new gear verbally or fills out a requisition form, both just update the same official kit list — there's no hidden magic beyond that entry plus the warehouse fetching the actual gear.

Semantic versioning and lock files

NuGet packages follow semantic versioning (MAJOR.MINOR.PATCH) by convention, and version ranges can be specified (e.g. [8.0.0,9.0.0)), though pinning an exact version is the most common and predictable approach for application projects. For reproducible builds across machines and CI, teams can enable a packages.lock.json file (<RestorePackagesWithLockFile>true</RestorePackagesWithLockFile>), which pins the exact resolved dependency graph so a transitive dependency's silent version bump can't change behavior between builds without an explicit lock file update.

🏏

Cricket analogy: Bat models follow a naming convention like generation.grade.batch, and while a team could accept 'any bat from this generation' as a version range, most professional squads pin the exact certified bat model for the whole season; a locked equipment manifest ensures no supplier can silently swap in a slightly different bat batch before a big match.

Central Package Management

For multi-project solutions, Central Package Management (a Directory.Packages.props file at the solution root with <ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>) lets every project reference a package by ID only, with the version pinned once centrally — eliminating the common problem of different projects in the same solution silently drifting to different versions of the same dependency.

🏏

Cricket analogy: A national board's central kit standard lets every regional team reference 'team bat' by name only, with the exact model pinned once at board level — eliminating the problem of different regional squads silently drifting to different bat generations.

NuGet is conceptually similar to npm for JavaScript or Maven/Gradle for Java, but it's tightly integrated into the .NET SDK's build and restore pipeline rather than being a separate tool layered on top — dotnet build transparently triggers restore, and package references are just another MSBuild item type.

Adding a package with a wide or floating version range (e.g. a wildcard 8.*) can silently pull in a new version — including breaking changes — on a future dotnet restore with no code change, which is a common source of 'it worked yesterday' build failures; prefer exact versions or narrow ranges, and use a lock file for anything deployed to production.

  • NuGet is .NET's package manager, distributing versioned libraries as .nupkg packages via nuget.org or private feeds.
  • SDK-style .csproj files declare dependencies with <PackageReference Include="..." Version="..." />.
  • dotnet restore downloads packages and resolves the full transitive dependency graph into a local cache.
  • packages.lock.json pins the exact resolved dependency graph for reproducible builds across machines.
  • Central Package Management (Directory.Packages.props) centralizes version pinning across a multi-project solution.
  • Wide/floating version ranges risk silent, unreviewed upgrades on restore — prefer exact pinned versions in production.

Practice what you learned

Was this page helpful?

Topics covered

#CStudyNotes#Programming#NuGetPackages#NuGet#Packages#PackageReference#Modern#StudyNotes#SkillVeris#ExamPrep