Skip to content

Repository files navigation

DotnetDeployer logo

DotnetDeployer

Deploy your .NET projects with a single YAML file. No scripts. No ceremony. Just ship it.


Why?

Let's be honest: CI/CD pipelines are powerful, but they're also way too complicated for what most projects need. You want to push a NuGet package or create a GitHub Release with some binaries. That's it. But instead, you end up wrestling with YAML indentation, provider-specific syntax, environment variables, and a dozen moving parts.

Tools like Nuke are fantastic for complex scenarios, but they come with their own learning curve and boilerplate. Sometimes you just want to declare what you want to deploy and let something else figure out the how.

That's DotnetDeployer. Write a simple deployer.yaml, run the tool, and you're done.


What does it do?

DotnetDeployer handles the boring parts of deployment:

  • NuGet packages: Pack and push all packable projects in your solution
  • GitHub Releases: Build platform-specific packages (AppImage, DEB, RPM, EXE, DMG, MSIX, APK, AAB) and upload them as release assets
  • GitHub Pages: Deploy WebAssembly apps directly to GitHub Pages
  • Automatic versioning: Integrates with GitVersion out of the box
  • CI-friendly: Outputs ##vso[build.updatebuildnumber] for Azure Pipelines (and similar patterns for other CI systems)

Quick Start

1. Create deployer.yaml

version: 1nuget:
enabled: truesource: https://api.nuget.org/v3/index.jsonapiKey:
from: secretkey: nuget_api_key

2. Run the tool

# From source (self-deployment style)
dotnet run --project path/to/DotnetDeployer.Tool.csproj
# Or install as a global tool
dotnet tool install -g DotnetDeployer.Tool
dotnetdeployer secrets set nuget_api_key
dotnetdeployer

3. That's it

The tool will:

  • Detect your solution
  • Use GitVersion to determine the version
  • Pack all packable projects
  • Push to NuGet (or simulate with --dry-run)

Full Configuration Example

version: 1nuget:
enabled: truesource: https://api.nuget.org/v3/index.jsonapiKey:
from: secretkey: nuget_api_keygithub:
enabled: trueowner: YourGitHubUsernamerepo: YourRepotoken:
from: secretkey: github_tokenoutputDir: artifactspackages:
- project: src/MyApp.Desktop/MyApp.Desktop.csprojformats:
- type: appimagearch: [x64, arm64]
- type: debarch: [x64]
- type: exe-setuparch: [x64]
- type: dmgarch: [x64, arm64]githubPages:
enabled: trueowner: YourGitHubUsernamerepo: MyApp-Pagestoken:
from: secretkey: github_tokenproject: src/MyApp.Browser/MyApp.Browser.csproj

CLI Options

OptionDescription
--config, -cPath to deployer.yaml (default: deployer.yaml)
--dry-run, -nSimulate deployment without making changes
--release-version, -vOverride version for the release
--package-onlyGenerate packages without publishing NuGet, GitHub Releases, or GitHub Pages
--package-projectSelect one github.packages[].project entry when the YAML has multiple package projects
--package-targetGenerate a target in <type>:<arch> form, e.g. exe-setup:x64; can be repeated
--output-dirOverride the directory where generated packages are written

Secrets are managed with a subcommand:

dotnetdeployer secrets set nuget_api_key
dotnetdeployer secrets check nuget_api_key
dotnetdeployer secrets delete nuget_api_key

secrets set stores values in the system keyring: Windows Credential Manager, macOS Keychain, or Linux Secret Service through secret-tool. A from: secret value still reads deployer.secrets.yaml first, then falls back to the keyring.

See Secret Management for the full keyring, Android signing, and CI guidance.

Generate only selected packages:

dotnetdeployer --package-only \
--package-project src/MyApp.Desktop/MyApp.Desktop.csproj \
--package-target exe-setup:x64 \
--package-target msix:x64 \
--output-dir artifacts/manual-build

Azure Pipelines Integration

DotnetDeployer can deploy itself. Here's how:

trigger:
- master
- mainvariables:
- group: api-keys
- name: Agent.Source.Git.ShallowFetchDepthvalue: 0pool:
vmImage: 'ubuntu-latest'steps:
- checkout: selffetchDepth: 0
- pwsh: dotnet run --project src/DotnetDeployer.Tool/DotnetDeployer.Tool.csproj -- --dry-rundisplayName: Dry run (PRs)condition: and(succeeded(), ne(variables['Build.SourceBranch'], 'refs/heads/master'))env:
NUGET_API_KEY: $(NugetApiKey)
- pwsh: dotnet run --project src/DotnetDeployer.Tool/DotnetDeployer.Tool.csprojdisplayName: Deploycondition: and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/master'))env:
NUGET_API_KEY: $(NugetApiKey)

The tool automatically outputs ##vso[build.updatebuildnumber] to set the build name to the detected version.


Supported Package Types

PlatformTypes
LinuxAppImage, DEB, RPM
WindowsEXE (self-extracting), EXE (setup wizard), MSIX
macOSDMG
AndroidAPK, AAB

Android Keystore Configuration

Android packages (APK/AAB) can be release-signed. DotnetDeployer supports three keystore sources with an explicit, expanded YAML syntax.

Source 1: Physical file

android:
signing:
keystore:
from: filepath: ./android/release.keystorestorePassword:
from: secretkey: android_store_passkeyAlias: release-keykeyPassword:
from: secretkey: android_key_pass

Source 2: Environment variable (base64)

android:
signing:
keystore:
from: envname: ANDROID_KEYSTORE_BASE64encoding: base64storePassword:
from: secretkey: android_store_passkeyAlias: release-keykeyPassword:
from: secretkey: android_key_pass

Source 3: Named secret (keyring or secrets file)

android:
signing:
keystore:
from: secretkey: android_keystore_base64encoding: base64storePassword:
from: secretkey: android_store_passkeyAlias: release-keykeyPassword:
from: secretkey: android_key_pass

Store these values with dotnetdeployer secrets set <key>, or use a deployer.secrets.yaml in the repo root (add it to .gitignore):

android_keystore_base64: <base64-encoded-keystore-content>android_store_pass: <store-password>android_key_pass: <key-password>

Encoding your keystore

base64 -w 0 < your-release.keystore

Keystore source reference

Propertyfrom: filefrom: envfrom: secret
path✅ Required
name✅ Required
key✅ Required
encodingbase64base64

Per-format signing (alternative)

You can also configure signing per package format instead of at the top level:

github:
packages:
- project: src/MyApp.Android/MyApp.Android.csprojformats:
- type: apksigning:
keystore:
from: envname: ANDROID_KEYSTORE_BASE64encoding: base64storePassword:
from: secretkey: android_store_passkeyAlias: release-keykeyPassword:
from: secretkey: android_key_pass

About

Life should be easier in the dotnet world ;)

Resources

Stars

3 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages