CLI tool
xoofx/dotnet-releaser avatar
xoofx/dotnet-releaser

dotnet-releaser: one command for the whole .NET release cycle

Easily build, run tests and coverage, cross-compile, package and publish your .NET library or application to NuGet and GitHub.

772 stars28 forksC#BSD-2-Clause

At a glance

What is it?
dotnet-releaser wraps dotnet build, test, pack, publish and nuget push into a single release pipeline, adds cross-compilation to nine CPU and OS targets, generates changelogs from pull requests and commits, and uploads the artifacts to NuGet and GitHub. It suits maintainers of a .NET library or app who want a repeatable release command, and it assumes you want its defaults.
Who is it for?
dotnet-releaser is the right tool for a maintainer of a .NET library or application who wants one command that builds, tests, packs, cross-compiles and publishes, and the wrong tool for a project that wants a hand-written release pipeline, an unusual target matrix, or per-release control over which artifacts go to which registry.
Can I use it commercially?
Yes. BSD-2-Clause is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 101 days ago.
What is it written in?
Mainly C#, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The whole release cycle behind one executable

dotnet-releaser is described as an all-in-one command line tool that automates the release cycle of .NET libraries and applications to NuGet and GitHub. The list of what it wraps is the actual feature list, and it is long: building, testing, running coverage, cross-compiling, packaging, creating release notes from pull requests and commits, and publishing.

Underneath, it drives the standard .NET SDK commands rather than replacing them. It wraps dotnet build, possibly across multiple solutions, dotnet test with automatic coverage support, dotnet pack for NuGet packages, dotnet publish for cross-compilation, and dotnet nuget push for publishing to a NuGet registry. On top of that it adds the parts a hand-rolled pipeline usually gets wrong: cross-compiled output for many platforms, release notes assembled from the version control history, and the upload of every artifact to the GitHub release for the matching tag.

The audience is a maintainer of a .NET library or application, and the tool is a global .NET tool, so the same command runs on a developer machine and in CI. The documentation says it requires the .NET 9.0 runtime to be installed.

It is also honest about its adoption. Under the heading of who is using it, the project says it is brand new and mainly used by the author for now, pointing readers at the .github/workflows folder and at release notes of a handful of applications and libraries.

Cross-compilation across nine targets and four package formats

The packaging matrix is the part of this tool that goes beyond the SDK. By default, dotnet-releaser cross-compiles the application and creates packages per platform:

| Platform | Packages | |-----------------------------------------|------------------| | `win-x64`, `win-arm64` | `zip` | `linux-x64`, `linux-arm64` | `rpm`, `deb`, `tar` | `osx-x64`, `osx-arm64` | `tar`

Windows gets a zip, Linux gets the three native package formats plus a tarball, and macOS gets a tarball. A .NET 6.0 or newer application is the stated input for cross-compilation.

The Linux packages are where the value is, because a deb or rpm is what a system package manager expects, and that is the step most hand-written pipelines skip. The documentation also mentions publishing the application as a service, with systemd the only supported option for now and only for the deb and rpm packages, so the service story is a Linux one and a partial one.

There is a Homebrew side to it as well. By default the tool creates a Homebrew repository and formula, for example user_or_org/homebrew-your-app-name, covering the tar files associated with the Linux and macOS targets. That is a lot of surface area to enable at once, and it is worth knowing which of it a given project actually wants before the first release.

Installing the tool and generating the configuration file

The tool is installed as a global .NET tool:

bash
dotnet tool install --global dotnet-releaser

bash

Then you move to the folder holding your solution or project file and run the new command, which creates a configuration file next to the solution:

bash
dotnet releaser new

bash

The generated file is a dotnet-releaser.toml, and the documented content is short, an msbuild section naming the project and a github section naming the user and the repository:

toml
[msbuild]
project = "Tonlyn.sln"
[github]
user = "xoofx"
repo = "Tomlyn"

bash

To try a full build locally, the documented command is:

bash
dotnet-releaser build --force dotnet-releaser.toml

bash

The --force flag is there because a local build publishes artifacts, and the tool makes you say that you mean it.

Every step listed in the defaults section can be configured or entirely disabled from this file, and the user guide is the reference for doing so. That is the key design point for an evaluator: the defaults are a starting position rather than a fixed behaviour, and the toml is the interface to change them.

The GitHub Actions integration and the permissions it demands

For CI, the tool exposes a run command, and the documentation frames the integration as simple. The workflow needs two permission grants, and the comments in the example explain why each one exists:

yaml
  permissions:
    # Required to create/update GitHub releases, tags, release notes and assets with GITHUB_TOKEN.
    # Use contents: read only if you do not publish anything back to GitHub.
    contents: write
    # Required by NuGet trusted publishing (`nuget.trusted_publishing = true`).
    id-token: write

The example then checks out with full history, installs .NET, and runs the release command with the token:

yaml
    steps:
    - name: Checkout
      uses: actions/checkout@v4
      with:
        fetch-depth: 0

    - name: Install .NET 10.0
      uses: actions/setup-dotnet@v4
      with:
        dotnet-version: '10.0.x'

    - name: Build, Tests, Cover, Pack and Publish (on push tag)
      shell: bash
      run: |
        dotnet tool install --global dotnet-releaser
        dotnet-releaser run --github-token "${{secrets.GITHUB_TOKEN}}" src/dotnet-releaser.toml

Two details are easy to get wrong. The checkout uses fetch-depth: 0, which is needed because the changelog is generated from the commit history. And the NuGet side uses trusted publishing with an id-token: write permission rather than a long-lived API key, with the classic key still available through a --nuget-token option if that is what the project uses.

One more edge is called out: when calling the tool from a reusable workflow, the permissions have to be granted on the caller job, and actions: write is not needed by the tool itself unless another step in the workflow calls the GitHub Actions API.

Changelogs assembled from pull requests and commits

The changelog is generated by extracting information directly from pull requests and commits, with customizable templates, and the result is uploaded to the GitHub release along with the package artifacts. The documentation calls this a pretty changelog and points to a user guide section for the template options.

This is the feature that turns the tool from a script into a release process, and it is also the feature most likely to surprise. A changelog derived from commit history is only as good as the commit and pull request discipline of the repository, so a team that writes commit messages like fix wip produces a release note that nobody reads. The templates are customizable, which means you can decide what a pull request title must contain for it to appear, but no template can invent information that was never written down.

The GitHub side of the publishing is also automated. Release artifacts and the changelog are uploaded on the tag associated with the package version, and the tool will look for a git tag named v1.0.0 or 1.0.0 to match a package version of 1.0.0. That tag convention is a small thing that decides whether the automatic upload lands on the right release, so it is worth aligning your tagging practice with it before the first run.

What the defaults actually do, and how to turn them off

It is worth listing the default behaviour in full, because the tool's value is that this list needs no attention, and its risk is that the list is longer than expected.

By default, dotnet-releaser builds your project or solution in Release, runs the tests in Release, creates NuGet packages for libraries and applications packed as a .NET global tool, creates application packages for any packable application in the project per the platform matrix, publishes libraries and applications to NuGet, uploads all the package artifacts and the changelog to GitHub on the matching tag, and creates a Homebrew repository and formula for the tar files of the Linux and macOS targets.

That is a complete release pipeline in a single command, and the flip side is that a project that wants a plain NuGet package and nothing else still gets a cross-compiled application, a Homebrew tap and a set of GitHub assets unless it turns them off.

The documentation states that any of these steps can be configured or even entirely disabled easily from a config file, and points to the user guide for how to set it up differently for your application. A reasonable first run is a local build with --force on a throwaway tag, checking the produced artifacts before letting the CI job publish anything.

Project maturity, licence and the shape of the repository

The project is C#, published to NuGet as dotnet-releaser, and released under the BSD-Clause 2 licence. The repository is not archived, and the last push was on 2026-07-14, with releases 0.24.0 and 0.23.0 on the same day and 0.22.0 on 2026-06-30, so the versioning is pre-1.0 and moving quickly.

Pre-1.0 is the thing to weigh. The tool wraps a large set of SDK commands and a set of publishing destinations, so its surface area is wide, and a 0.x version signals that interfaces may still change. The pin is easy to take in a workflow file, so the practical risk is lower than the number suggests.

The repository layout is conventional: src/, tests/, doc/ with the user guide and the changelog guide, plus a changelog.md at the root, a readme.md, an AGENTS.md and a CLAUDE.md. The presence of agent instruction files in the tree is itself a signal about how the project is developed now.

The BSD-2-Clause licence is permissive and short, with the usual obligations to keep the notice. This is not legal advice, and the licence text in license.txt is the version to read.

Editorial conclusion

dotnet-releaser is the right tool for a maintainer of a .NET library or application who wants one command that builds, tests, packs, cross-compiles and publishes, and the wrong tool for a project that wants a hand-written release pipeline, an unusual target matrix, or per-release control over which artifacts go to which registry. Before adopting it, generate a dotnet-releaser.toml with dotnet releaser new and read the user guide, since every default listed in the documentation, from the Release build configuration to the automatic Homebrew formula, can be reconfigured or switched off in that file.

Frequently asked questions

How do I install dotnet-releaser and create a configuration file?

Install it as a global .NET tool with dotnet tool install --global dotnet-releaser, then run dotnet releaser new in the folder holding your solution or project file. That creates a dotnet-releaser.toml next to the solution with an msbuild section and a github section.

Which platforms and package formats does dotnet-releaser produce by default?

Windows targets win-x64 and win-arm64 get a zip, Linux targets linux-x64 and linux-arm64 get rpm, deb and tar, and the osx-x64 and osx-arm64 targets get a tar. The application is also published as a service using systemd for the deb and rpm packages.

What GitHub Actions permissions does dotnet-releaser need?

The workflow needs contents: write to create and update releases, tags, release notes and assets with GITHUB_TOKEN, and id-token: write for NuGet trusted publishing. The checkout should use fetch-depth: 0 because the changelog is built from the commit history.

Can I use dotnet-releaser without GitHub Actions?

Yes. The same commands work locally or from GitHub Action, and the local build is dotnet-releaser build --force dotnet-releaser.toml. The tool requires the .NET 9.0 runtime to be installed.

How does dotnet-releaser match a package version to a GitHub release?

It uploads the artifacts and the changelog to GitHub on the tag associated with the package version, trying to find a git tag v1.0.0 or 1.0.0 for a package version of 1.0.0. The tag naming convention therefore decides where the release lands.

Official sources

  1. Issues
  2. License: BSD-2-Clause
  3. README
  4. Releases
  5. xoofx/dotnet-releaser on GitHub
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/xoofx-dotnet-releaser.svg)](https://hysenlabs.com/projects/xoofx-dotnet-releaser)

Was this useful?