Publish .NET packages

View .md

kanject packages is the release control plane for NuGet and SDK repositories. It turns the evaluated MSBuild graph into a reviewed public/private policy, proves versions are immutable, stages candidates to a real feed, builds clean consumers, and journals the approved publication.

You'll learn
  • Choose a split or all-private repository policy and classify every packable project
  • Gate closure, package metadata, version floors, and already-claimed identities before release
  • Stage unique -rc.N candidates and build consumers from the actual candidate feed
  • Promote only after approval, using a trusted publisher and a resumable operation journal

Use the right shipping family

Use kanject packages when the repository's product is one or more NuGet packages. Use kanject aws distribute when the product is a downloadable application routed by edition and runtime identifier. A legacy kind: "library" distribution cell still works for a deliberately product-coupled artifact, but it is not the normal authority for an SDK surface.

Start with policy, not a push command

init --split scaffolds a public/private policy and human-review list; --all-private creates the BaaS-style shape with no public destination. The policy names feed environment variables rather than embedding credentials. plan --write maintains the reviewable public list; verify is the blocking local and CI gate.

bash
# Pin the CLI in the repositorydotnet new tool-manifestdotnet tool install Kanject.Cli# Pick the repository shapedotnet kanject packages init --split# or: dotnet kanject packages init --all-private# Make the intended package surface reviewabledotnet kanject packages plan --writedotnet kanject packages verify --advisories
  • Closure: a public package cannot depend on a private first-party package.
  • Classification: every packable project resolves to one deliberate tier.
  • Contract: effective dependency floors cannot exceed the sibling versions being built.
  • Content: configured public metadata, license, symbol, and SourceLink rules are enforced.
  • Fail loud: an unreadable project graph or unknown policy member is a failure, never a skipped check.

Audit versions before anyone waits for approval

A package identity is permanently claimed by its version and contract. versions --packed-dir compares the packed payload plus normalized dependency contract with the destination feed. If the bytes or dependency contract moved, the project needs a new VersionPrefix; the CLI names it but never guesses whether the bump is patch, minor, or major.

bash
# Pack the exact release inputsdotnet pack Acme.Sdk.slnx -c Release -o packed# Refuse versions already claimed by different package contractsdotnet kanject packages versions   --packed-dir packed   --strict# Preserve the evaluated dependency graph as release evidencedotnet kanject packages graph --out package-graph.json

Evidence first, candidate second

The normal pipeline compiles once and packs twice: stable identities travel in the protected artifact, while the same assemblies are packed with a feed-derived -rc.N suffix for testing. The hostile build role has no release secret and can write only to the candidate repository.

bash
# Build-stage evidence — no package is pusheddotnet kanject packages publish   --profile release-evidence   --packed-dir packed# Candidate stage — writes only to the configured rc feeddotnet kanject packages publish   --profile candidate   --packed-dir packed-rc   --ci# Prove clean consumers restore and build from the real candidate feeddotnet kanject packages smoke feed   --plan release-plan-rc.json   --build

smoke feed --build installs each planned candidate into a clean consumer and builds it with analyzer failures elevated. Packages that need a runtime companion or literal source activation keep their isolated smoke and add a composite fixture; packages smoke fixture init scaffolds that proof fail-loud rather than inventing a green no-op fixture.

Approve the bytes that were tested

After a person validates the RC, the publish stage recomputes routing from deployment-owned inputs, byte-verifies any existing identity, pushes dependency-first, and records every operation. It installs the infrastructure-pinned released CLI—not the repository's candidate tool—and its buildspec is controlled by the release stack.

bash
# Trusted publish stage, after manual approvalPUBLISH_PUBLIC=true dotnet kanject packages publish   --profile approved-release   --packed-dir packed   --ci# A partial publication resumes from its durable journalPUBLISH_PUBLIC=true dotnet kanject packages publish   --profile approved-release   --packed-dir packed   --resume release-journal.json   --ci

The three receipts

Release plan
The exact package identities, routes, hashes, and policy fingerprint the release intends to execute.
Preflight verdicts
As-if-armed destination evidence created before mutation: absent, equivalent, or conflicting identity.
Publication journal
A durable per-operation record that makes partial releases observable and safely resumable.
Recap
  • packages init → plan → verify turns the real project graph into a deliberate, reviewable package surface.
  • versions --packed-dir --strict catches claimed identities before candidate staging.
  • Candidates live in a separate rc feed and must restore/build from that feed before approval.
  • The trusted publisher ships the approved stable packages dependency-first and persists plan, preflight, and journal evidence.
Was this page helpful?