How to Create a NuGet Package from a Batch Script
NuGet is the package manager for .NET, enabling developers to share reusable libraries, tools, and components. Creating a NuGet package (.nupkg) from a Batch Script automates the packaging process, ensuring consistent metadata, version numbering, and artifact generation as part of your build pipeline.
In this guide, we will explore how to create NuGet packages from a Batch Script using the dotnet pack command and the standalone nuget.exe tool, covering versioning, metadata configuration, and multi-project packaging.
Understanding NuGet Package Creation
There are two primary ways to create NuGet packages:
| Tool | Source | Best For |
|---|---|---|
dotnet pack | SDK-style .csproj projects | Modern .NET Core / .NET 5+ libraries |
nuget pack | .nuspec file or .csproj | Legacy .NET Framework projects |
Modern projects should use dotnet pack, which reads package metadata directly from the .csproj file.
Method 1: Basic Package Creation
@echo off
setlocal
set "project=MyLibrary"
set "config=Release"
set "output=artifacts\packages"
echo Creating NuGet package for %project%...
if not exist "%output%" mkdir "%output%"
dotnet pack "%project%" -c %config% -o "%output%"
if %errorlevel%==0 (
echo.
echo [SUCCESS] Package created:
dir /b "%output%\*.nupkg"
) else (
echo.
echo [ERROR] Package creation failed.
)
pause
Setting Package Metadata in .csproj
The package metadata is defined in the project file:
<PropertyGroup>
<PackageId>MyCompany.MyLibrary</PackageId>
<Version>1.0.0</Version>
<Authors>Your Name</Authors>
<Description>A useful library for doing things.</Description>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<PackageProjectUrl>https://github.com/mycompany/mylibrary</PackageProjectUrl>
<RepositoryUrl>https://github.com/mycompany/mylibrary.git</RepositoryUrl>
<PackageTags>utility;helpers</PackageTags>
</PropertyGroup>
Method 2: Package with Version Override
Pass the version number from the Batch Script:
@echo off
setlocal enabledelayedexpansion
set "project=MyLibrary"
set "config=Release"
set "output=artifacts\packages"
:: Read version
if exist VERSION (set /p "version=" < VERSION) else (set "version=1.0.0")
:: Build number
if exist BUILD_NUMBER (set /p "build=" < BUILD_NUMBER) else (set "build=0")
set /a build+=1
>"BUILD_NUMBER" echo !build!
set "pkg_version=!version!.!build!"
echo =============================================
echo NUGET PACKAGE
echo Project: %project%
echo Version: !pkg_version!
echo =============================================
echo.
if not exist "%output%" mkdir "%output%"
dotnet pack "%project%" -c %config% -o "%output%" ^
/p:PackageVersion=!pkg_version! ^
/p:Version=!pkg_version!
if !errorlevel!==0 (
echo.
echo [SUCCESS] Package created:
dir /b "%output%\*.nupkg"
) else (
echo [ERROR] Failed.
)
pause
Method 3: Pre-Release Package
Create a pre-release (beta, alpha, RC) version:
@echo off
setlocal enabledelayedexpansion
set "project=MyLibrary"
set "config=Release"
set "output=artifacts\packages"
:: Read base version
if exist VERSION (set /p "version=" < VERSION) else (set "version=1.0.0")
echo.
echo Current version: !version!
echo.
echo Package type:
echo [1] Release (!version!^)
echo [2] Beta (!version!-beta^)
echo [3] Alpha (!version!-alpha^)
echo [4] RC (!version!-rc.1^)
echo [5] Custom suffix
set /p "choice=Select: "
set "pkg_version="
if "!choice!"=="1" set "pkg_version=!version!"
if "!choice!"=="2" set "pkg_version=!version!-beta"
if "!choice!"=="3" set "pkg_version=!version!-alpha"
if "!choice!"=="4" set "pkg_version=!version!-rc.1"
if "!choice!"=="5" (
set /p "suffix=Enter suffix (e.g., preview.3): "
set "pkg_version=!version!-!suffix!"
)
if not defined pkg_version (
echo [ERROR] Invalid selection.
pause
exit /b 1
)
echo.
echo Creating package: %project%.!pkg_version!.nupkg
echo.
if not exist "%output%" mkdir "%output%"
dotnet pack "%project%" -c %config% -o "%output%" /p:PackageVersion=!pkg_version!
if !errorlevel!==0 (
echo [SUCCESS] Package created.
dir /b "%output%\*!pkg_version!*"
) else (
echo [ERROR] Failed.
)
pause
NuGet pre-release versions follow SemVer conventions. Packages with suffixes like -beta, -alpha, or -rc.1 are treated as pre-release and are hidden from consumers unless they explicitly opt-in to pre-release packages.
Method 4: Full Pack Pipeline
A production-grade pipeline that builds, tests, and packages:
@echo off
setlocal enabledelayedexpansion
set "project=MyLibrary"
set "test_project=MyLibrary.Tests"
set "config=Release"
set "output=artifacts\packages"
if exist VERSION (set /p "version=" < VERSION) else (set "version=1.0.0")
echo =============================================
echo NUGET PACK PIPELINE
echo %project% v%version%
echo =============================================
echo.
:: Stage 1: Restore
echo [1/4] Restoring...
dotnet restore "%project%" -v quiet
if !errorlevel! neq 0 (
echo [FAIL] Restore failed.
pause
exit /b 1
)
echo OK.
:: Stage 2: Build
echo [2/4] Building...
dotnet build "%project%" -c %config% --no-restore -v quiet
if !errorlevel! neq 0 (
echo [FAIL] Build failed.
pause
exit /b 1
)
echo OK.
:: Stage 3: Test
echo [3/4] Testing...
dotnet test "%test_project%" -c %config% -v quiet
if !errorlevel! neq 0 (
echo [FAIL] Tests failed. Aborting package creation.
pause
exit /b 1
)
echo OK.
:: Stage 4: Pack
echo [4/4] Packing...
if not exist "%output%" mkdir "%output%"
dotnet pack "%project%" -c %config% --no-build -o "%output%" ^
/p:PackageVersion=%version%
if !errorlevel!==0 (
echo.
echo =============================================
echo PACKAGE READY
for %%F in ("%output%\*.nupkg") do (
echo File: %%~nxF
echo Size: %%~zF bytes
)
echo =============================================
) else (
echo [FAIL] Pack failed.
pause
exit /b 1
)
pause
Method 5: Multi-Project Packaging
Package multiple libraries from a solution:
@echo off
setlocal enabledelayedexpansion
set "config=Release"
set "output=artifacts\packages"
if exist VERSION (set /p "version=" < VERSION) else (set "version=1.0.0")
echo =============================================
echo MULTI-PROJECT PACK v%version%
echo =============================================
echo.
if not exist "%output%" mkdir "%output%"
set "projects=src\Core\Core.csproj src\Abstractions\Abstractions.csproj src\Extensions\Extensions.csproj"
set "packed=0"
for %%P in (%projects%) do (
echo Packing %%~nP...
dotnet pack "%%P" -c %config% -o "%output%" /p:PackageVersion=%version% -v quiet
if !errorlevel!==0 (
echo [OK]
set /a packed+=1
) else (
echo [FAIL]
)
)
echo.
echo [DONE] Packed !packed! packages to %output%
echo.
dir /b "%output%\*.nupkg"
pause
Inspecting a Package
Verify the contents of a created package:
@echo off
set "package=artifacts\packages\MyLibrary.1.0.0.nupkg"
if not exist "%package%" (
echo [ERROR] Package not found: %package%
pause
exit /b 1
)
echo Package contents:
echo =================
echo.
:: NuGet packages are ZIP files
powershell -noprofile -command ^
"Add-Type -AssemblyName System.IO.Compression.FileSystem; ^
$zip = [System.IO.Compression.ZipFile]::OpenRead('%package%'); ^
$zip.Entries | Sort-Object FullName | ForEach-Object { ^
Write-Host ('{0,10:N0} {1}' -f $_.Length, $_.FullName) ^
}; ^
$zip.Dispose()"
pause
Common Mistakes
The Wrong Way: Packing Without Building First
:: WRONG - May package stale or missing compiled output
dotnet pack MyLibrary -c Release --no-build
:: If the project was not built, the package will be empty or fail
Output Concern:
Using --no-build without a preceding dotnet build results in an empty or incomplete package. Either omit --no-build (which triggers an implicit build) or ensure a successful build step before packing.
The Wrong Way: Not Setting Package Metadata
:: WRONG - Package has default/missing metadata
dotnet pack MyLibrary -o packages
:: Package ID defaults to project name, no description, no author
Packages without proper metadata (description, author, license) will be rejected by NuGet.org and are hard to identify in private feeds. Always configure metadata in the .csproj file.
Best Practices
- Define metadata in
.csproj: Include PackageId, Version, Authors, Description, and License. - Use
--no-buildafter a verified build: Avoid redundant compilation in pipeline scripts. - Version from a single source: Pass
/p:PackageVersionfrom a VERSION file or CI variable. - Test before packing: Never create packages from untested code.
- Inspect packages before publishing: Verify contents match expectations.
Conclusion
Creating NuGet packages from a Batch Script is handled by the dotnet pack command, which reads metadata from the .csproj file and produces a .nupkg archive. By integrating version management, pre-release suffixes, and multi-project packaging into build pipelines, teams create consistent, well-identified library packages ready for distribution through NuGet.org or private feeds. The pack pipeline pattern (restore, build, test, pack) ensures every published package is compiled, verified, and properly versioned.