This is the published account of how a dotnet-fast release is produced and what comes with it. It is
not a build-from-source guide — the tool ships as a binary and its source is proprietary
(LICENSE) — it is here so you can judge what "a new version shipped" actually means
before you pin one in CI.
dotnet-fast follows Semantic Versioning. What each segment means here — and the
CLI-contract and deprecation rules that decide which segment moves — is in
versioning.md; that page is the compatibility promise, this one is the process
behind it.
One version identifies everything in a release: the NuGet package version, the release tag (vX.Y.Z —
the same number with a v prefix), and what dotnet-fast --version prints (1.2.0, bare) all refer
to the same build. There is no separate build number, and a published version is never re-cut with
different content.
The current stable line is the newest entry in RELEASES.md; this page does not
restate it, because a hardcoded number here goes stale the moment a release ships. The compatibility
rules in versioning.md were already how we worked before 1.0; from 1.0 they are a
formal promise rather than a working practice, and a break in them costs a major version.
One version has no NuGet package: 1.0.1 was tagged and never published, and everything in it
shipped in 1.1.0. Pinning it in .config/dotnet-tools.json will fail to restore.
A pre-release version carries a suffix (1.0.0-rc.1) and is published as a pre-release on both
NuGet and GitHub, so dotnet tool install and the GitHub "latest release" link keep resolving the
stable line until the final version ships. Installing one is always explicit — see
RELEASES.md for the commands.
- The NuGet package
RDLL.dotnet-fast— the supported way to install and update (dotnet tool install -g RDLL.dotnet-fast/dotnet tool update -g RDLL.dotnet-fast). - A plain-English entry in RELEASES.md for anything user-visible, with anything action-required stated first.
- Updated documentation on this site when the command surface or the lint rule catalog changed.
- Self-contained
dotnet-fast-win-x64.exeanddotnet-fast-linux-x64binaries (each with its own.sha256), built from the same commit and attached to that version's GitHub release on this repository. Since1.2.0win-x64 is a published artifact rather than an internal one; since1.10.1linux-x64 joins it. - A tag on these docs. Each release commits the documentation as it stood for that version and
tags it
vX.Y.Z, so you can read what a page said at the version you are running rather than only its current state.
The checksum next to the binary detects a corrupted or truncated download; it is not a signature, and
anyone able to replace the file could replace the checksum beside it. NuGet remains the recommended
channel — it is the one with a third-party signature (security.md). If what you want
is a CI agent that does not pay a tool restore per job, installing once with
dotnet tool install RDLL.dotnet-fast --tool-path <dir> and caching <dir> keeps that signature in
the picture.
The NuGet package is the artifact with an integrity story, and it is not one we produce ourselves —
nuget.org repository-signs the package on ingestion, which anyone can check with dotnet nuget verify.
We publish no author signature, no code signature, and no build-provenance attestation. The full
position for 1.0, including why build attestation and a SLSA level are not claimed, is in
security.md.
These run before the version is tagged and published, so a failure means no release — not a release followed by a hotfix.
Not every gate is the same kind of thing, and it would be misleading to present them as one list. Some are automated and run on every single release; others are run deliberately, when the change is the kind that can break what they check. Both are stated below, labelled.
The release command runs these itself and stops on the first failure:
- Build hygiene and the full automated test suite — a warning-free build and lint of the tool's own source, then the complete unit and CLI integration suite.
- CLI-contract golden tests — every command's help text, output shape, and exit codes are pinned by golden files. Changing any of them fails the suite rather than reaching your pipeline. This is the mechanical half of the compatibility promise in versioning.md. Part of the test suite, so it runs on every test run too.
- The parity-regression ledger — every formatting divergence anyone reports becomes a permanent test
case: the reported input, plus the real
dotnet formatoutput as the expectation, generated from a compilable probe. The fix always goes into the formatter, never into the expectation. This suite runs on every test run, not only on formatter changes, so a divergence that has been reported once cannot come back quietly. - Differential formatter parity against the real
dotnet format— 146 fixtures are formatted bydotnet-fastand by the realdotnet formatfrom the installed .NET SDK (10.x), then byte-compared. The expectation is the oracle's actual output, not a hand-written file. - Documentation drift — a test asserts that every native rule that ships is documented, that the
published
fix/report-onlymarker for each one matches what the code actually does, and that the rule counts quoted in the docs — including the verbatimlint --list-rulesheader on install.md — match the catalog. A rule added, removed, or made unfixable without the documentation following fails the build rather than shipping a page that lies. (Theinstall.mdtranscript was NOT covered until 2026-08-03: withdrawing RCS0062's autofix dropped the fixable total from 145 to 144 and the page shipped stale with a green suite. That gap is what the check now closes.)
There is an escape hatch on the parity gate for releases that cannot touch the formatter (a docs-only or packaging-only cut). Using it prints a loud warning naming the version that shipped without parity verification. It is not used for a change that touches formatting.
These are not run by the release command. They are heavier, and each one is run when a change is of the kind it can catch:
- A whole-repository parity sweep, for formatter changes — five real open-source repositories
(Newtonsoft.Json, Polly, Dapper, AutoMapper, Serilog) are formatted end to end by both tools and
compared file by file. Each repository has a published floor in
support-matrix.md; a change that would drop any of them below its floor does
not ship as-is. The floors on that page carry the date they were last measured. The sweep also
verifies that both tools processed the same files and fails when they did not — a percentage
computed over files only one tool opened is not evidence of parity. As of 2026-08-03 four of the five
clear that check: Dapper started clearing it once the
#if-region parsing defects behind its one-sided files were fixed, and Newtonsoft.Json now fails it on one file for a documented, pre-existing final-line edge case that does not affect its parity figure. Both are explained in support-matrix.md. - Real-world fix safety, for changes to any automatic fix — a set of open-source repositories is
fixed and then compiled. Fixed code that no longer builds is the failure mode that fixture corpora
cannot see (preprocessor directives,
#pragmaregions, and parse edge cases are the recurring culprits), so the compile step is the gate that catches it. - The benchmark floor, for performance-affecting changes — the medium and large tiers are re-run
with output verification and fail if any scenario drops below 2× versus
dotnet format. The methodology, and the date of the last recorded run, are in benchmarks.md. A published speed number is verified as of its stated date; it is not re-verified on every release.
Two things worth stating plainly:
- The parity gates need a real .NET SDK, and the oracle is not perfectly deterministic. On at least
one known input shape,
dotnet formatitself settles on two different results across runs of identical code. Where that happens the affected fixture is re-run in isolation and the release proceeds only if it then passes cleanly; the expectation is never relaxed to make a failure go away. - Every gate, and the packaging, runs on Windows x64 — there is no non-Windows step anywhere. That
is why Windows x64 is the only supported platform: the package carries a
win-x64native binary only, so a Linux or macOS install succeeds and then fails on first run. Read support-matrix.md before planning around either.
- NuGet publication uses NuGet's Trusted Publishing (OIDC). The publish job exchanges a short-lived identity token for a single-use API key valid for one hour. There is no long-lived NuGet API key for this package — nothing stored to leak, nothing to rotate.
- Nothing publishes itself. No commit, merge, or schedule triggers a release; every publish is started deliberately by the maintainer.
- Dependency advisories are scanned daily, independently of release cadence (RustSec advisory database, plus license and source policy). A vulnerability disclosed between releases surfaces within a day rather than at the next release.
There is no fixed release train. Releases go out when a feature wave or a fix is ready, which in practice means patch and minor releases land often. A reproducible user-reported bug is normally fixed in the next release rather than held for a milestone — 0.306.1 is a worked example of that path, including what it changed and why.
Ahead of a significant release, a pre-release may be published under an -rc suffix (for example
1.0.0-rc.1) so it can be validated in real pipelines before the final tag. Pre-releases are outside
the compatibility promise — see versioning.md.
- RELEASES.md — plain-English notes, newest first, with anything action-required called out at the top of the entry.
- nuget.org/packages/RDLL.dotnet-fast — the version history of what is actually live, including any pre-releases.
dotnet-fast --version— the bare version you are running right now, matching aRELEASES.mdheading.
If a release note doesn't explain a change you can see, that's a bug in the notes: open an issue and it'll be corrected.
☕ Find dotnet-fast useful? Buy me a coffee — thanks for the support!