iwantcoding.com
🔥 Daily 👥 Rooms 🏆 Top Log in Sign up

NuGet / dotnet CLI

NuGet is the .NET package manager. Use dotnet CLI for restore + install + publish; ship a .nuspec or PackageReference-based csproj; sign packages for trust; pin versions for reproducibility.

Install, build, pack, push, version

EXAMPLE
# ===== 1) Install packages =====
# Add a dependency
dotnet add package Microsoft.Extensions.Logging
dotnet add package Serilog --version 4.0.0
dotnet add package Polly --version 8.0.0

# Or edit .csproj directly
# <ItemGroup>
#   <PackageReference Include=\"Serilog\" Version=\"4.0.0\" />
# </ItemGroup>

# Restore (downloads to ~/.nuget/packages)
dotnet restore

# ===== 2) Pin versions =====
# Use a Directory.Packages.props to centralise versions across projects:
# <Project>
#   <PropertyGroup>
#     <ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
#   </PropertyGroup>
#   <ItemGroup>
#     <PackageVersion Include=\"Serilog\" Version=\"4.0.0\" />
#     <PackageVersion Include=\"FluentAssertions\" Version=\"6.12.0\" />
#   </ItemGroup>
# </Project>
#
# Then each csproj just lists the package without a version:
# <PackageReference Include=\"Serilog\" />

# ===== 3) Pack your own library =====
# YourLib.csproj
# <Project Sdk=\"Microsoft.NET.Sdk\">
#   <PropertyGroup>
#     <TargetFrameworks>net8.0;netstandard2.0</TargetFrameworks>
#     <PackageId>YourCompany.YourLib</PackageId>
#     <Version>1.0.0</Version>
#     <Authors>YourCompany</Authors>
#     <Description>What this library does</Description>
#     <PackageLicenseExpression>MIT</PackageLicenseExpression>
#     <PackageProjectUrl>https://github.com/yourorg/yourlib</PackageProjectUrl>
#     <RepositoryUrl>https://github.com/yourorg/yourlib</RepositoryUrl>
#     <RepositoryType>git</RepositoryType>
#     <PackageReadmeFile>README.md</PackageReadmeFile>
#     <PublishRepositoryUrl>true</PublishRepositoryUrl>
#     <EmbedUntrackedSources>true</EmbedUntrackedSources>
#     <IncludeSymbols>true</IncludeSymbols>
#     <SymbolPackageFormat>snupkg</SymbolPackageFormat>
#   </PropertyGroup>
#
#   <ItemGroup>
#     <None Include=\"README.md\" Pack=\"true\" PackagePath=\"\\" />
#   </ItemGroup>
# </Project>

dotnet pack -c Release
# Output: bin/Release/YourCompany.YourLib.1.0.0.nupkg + .snupkg (symbols)

# ===== 4) Publish to NuGet.org =====
dotnet nuget push bin/Release/YourCompany.YourLib.1.0.0.nupkg \
  --api-key $NUGET_API_KEY --source https://api.nuget.org/v3/index.json

# ===== 5) Private feed (GitHub Packages, Azure Artifacts, BaGet) =====
# nuget.config
# <configuration>
#   <packageSources>
#     <add key=\"github\" value=\"https://nuget.pkg.github.com/yourorg/index.json\" />
#   </packageSources>
#   <packageSourceCredentials>
#     <github>
#       <add key=\"Username\" value=\"yourorg\" />
#       <add key=\"ClearTextPassword\" value=\"%GITHUB_TOKEN%\" />
#     </github>
#   </packageSourceCredentials>
# </configuration>
#
# dotnet nuget push pkg.nupkg --source github

# ===== 6) Sign packages (recommended for distribution) =====
dotnet nuget sign pkg.nupkg --certificate-path cert.pfx --certificate-password $PFX_PW \
  --timestamper http://timestamp.digicert.com

# Verify
dotnet nuget verify pkg.nupkg

# ===== 7) SemVer + pre-release =====
# Stable: 1.0.0
# Prerelease: 1.0.0-rc.1, 1.0.0-beta.1
# Floating version in PackageReference: <PackageReference Version=\"6.*\" />
# Avoid floats in production for reproducibility.

# ===== 8) Reproducible builds =====
# Set <ContinuousIntegrationBuild>true</ContinuousIntegrationBuild> in csproj
# Use deterministic builds: <Deterministic>true</Deterministic>
# Pin dotnet SDK version with global.json:
# { \"sdk\": { \"version\": \"8.0.100\", \"rollForward\": \"latestFeature\" } }

# ===== 9) Audit + vulnerability check =====
dotnet list package --vulnerable
dotnet list package --outdated
dotnet list package --deprecated
# Or run trivy / dotnet-retire / GitHub Dependabot

# ===== 10) Local development of a package =====
# Build .nupkg
dotnet pack -c Debug
# Add a local feed
dotnet nuget add source $(pwd)/bin/Debug --name local
# Reference the local version in another project
dotnet add package YourCompany.YourLib --source local

# OR use ProjectReference instead of PackageReference during development
# <ProjectReference Include=\"..\YourLib\YourLib.csproj\" />

# ===== 11) GitHub Actions to publish on tag push =====
# .github/workflows/publish.yml
# name: publish
# on:
#   push:
#     tags: [\"v*\"]
# jobs:
#   publish:
#     runs-on: ubuntu-latest
#     steps:
#       - uses: actions/checkout@v4
#       - uses: actions/setup-dotnet@v4
#         with: { dotnet-version: \"8.0.x\" }
#       - run: dotnet pack -c Release -p:Version=${{ github.ref_name#v }}
#       - run: dotnet nuget push **/*.nupkg --api-key ${{ secrets.NUGET_API_KEY }} --source https://api.nuget.org/v3/index.json

# ===== 12) Pitfalls =====
# - Floating versions (1.*) in production -> surprise upgrades
# - Forgetting symbol packages -> debugging consumers gets harder
# - No README.md in the package -> nuget.org page looks empty
# - PackageId without an owner prefix -> name collisions
# - Pushing without --skip-duplicate -> re-pushing the same version errors

Why it matters

Centralise package versions via Directory.Packages.props from day one. The repo gets a single source of truth, version drift across projects becomes impossible, and bumping a dependency is one file edit + green CI rather than find-and-replace across N csproj files.

Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.

Example

Example
dotnet add package Serilog
dotnet add package Microsoft.EntityFrameworkCore
dotnet restore
Try it Yourself »

Discussion

Loading…