Publish and consume NuGet packages.
Create a project-owned feed, give each client the minimum token scope, and move a package from a local build or exact pipeline artifact into a traceable release.
Separate feed administration from package use.
Prerequisites
- A verified Mozaic account and membership in the organization that owns the project.
- An existing project. Every feed belongs to one project; there is no personal package namespace.
- The claim at the project or organization scope to create feeds, issue credentials, change lifecycle state, or configure upstreams.
- A fresh sign-in for credential creation and destructive lifecycle actions.
- A current .NET SDK for the
dotnetCLI workflows below.
Feed management permission does not become a NuGet client credential. Create a separately scoped, expiring token for each developer workstation or automation client.
Create a private project feed.
- Choose New feed.Use a name people will recognize in the project package picker.
- Set the slug.Use lowercase letters, digits, and internal hyphens. The slug identifies the feed in Mozaic, while clients use the generated service-index URL.
- Understand the fixed defaults.The current creation form always makes the feed private and permits explicitly addressed restores of unlisted versions; those values are shown in the feed inventory rather than chosen in this form.
- Create the feed.Return to the feed inventory and copy the generated service-index URL.
Success state
The feed appears under Packages and exposes a NuGet v3 service index with this shape: https://<app-host>/nuget/<feed-id>/v3/index.json. Copy the displayed URL; the path contains the immutable feed ID, not its slug.
Feed names contain 1-120 characters. Slugs are at most 63 ASCII characters and contain lowercase letters, digits, and hyphens, with no leading or trailing hyphen.
Issue one show-once token per client.
Credential creation requires fresh authentication and Manage packages. The raw value begins with mznuget_, is displayed once, and cannot be recovered later.
read- Read a private feed, search packages, and restore package bytes.
push- Publish primary
.nupkgfiles whose normalized IDs match the token pattern. push_symbols- Publish
.snupkgor symbols-package bytes for matching package IDs. lifecycle- Unlist through NuGet delete and perform permitted package lifecycle operations.
- Name the client.Use a name such as
Ada workstation
orrelease automation
; names contain 1-120 characters. - Constrain package IDs.Enter one exact ID, a prefix with one trailing wildcard such as
Contoso.*, or*only when the client truly needs the whole feed. - Select scopes.At least one is required. Restore-only clients normally need only read; a release client commonly needs push and push symbols.
- Set expiry.Enter 1-8,760 hours (up to 365 days) in the current creation form.
- Copy and store the token.Put it directly into the intended credential store or CI secret, then close the show-once view.
A token authenticates its owner and scopes. Revocation, expiry, feed ownership, and the user's current organization authorization are still enforced; issuing a token does not preserve removed access.
Connect the dotnet CLI.
Use the exact service-index URL from the feed page. NuGet accepts a non-secret username; Mozaic authenticates the password value.
dotnet nuget add source "https://<app-host>/nuget/<feed-id>/v3/index.json" \
--name mozaic \
--username token \
--password "<show-once-mznuget-token>" \
--store-password-in-clear-text
dotnet nuget list source
The clear-text flag is needed on clients without a supported encrypted NuGet credential store. It writes the token to the user's NuGet configuration, so protect that file with operating-system permissions and never add it to the repository. Prefer an environment-provided temporary NuGet configuration in automation.
dotnet nuget add source "https://<app-host>/nuget/<feed-id>/v3/index.json" \
--name mozaic-public
Success state
dotnet nuget list source shows the new source as enabled, and requesting the service index returns NuGet resources rather than an authentication error.
Use the feed without changing project-wide sources.
dotnet package search Contoso.Widget --source mozaic --exact-match
dotnet add src/MyApp/MyApp.csproj package Contoso.Widget \
--version 1.2.3 \
--source mozaic
dotnet restore MySolution.slnx --source mozaic
Search and version discovery return listed, explicitly published, non-quarantined versions. If the feed allows unlisted restore, a client requesting an exact unlisted version can still restore it; broad search and version enumeration will not rediscover it.
For repeatable builds, commit package references and a lock file, but not credentials. Keep the source URL in NuGet.config only if it is safe for every repository reader to know; put authentication in a user or build-time configuration.
Push packages and symbols deliberately.
dotnet pack src/Contoso.Widget/Contoso.Widget.csproj \
--configuration Release \
--output ./artifacts/packages \
-p:IncludeSymbols=true \
-p:SymbolPackageFormat=snupkg
dotnet nuget push "./artifacts/packages/Contoso.Widget.1.2.3.nupkg" \
--source "https://<app-host>/nuget/<feed-id>/v3/index.json" \
--api-key "<push-token>" \
--symbol-api-key "<push-token>"
- Inspect the package locally.Confirm ID, version, dependency ranges, license metadata, and intended files before uploading immutable release coordinates.
- Use a matching token.The normalized package ID must match its exact or trailing-wildcard pattern. Primary and symbol uploads require their corresponding scopes.
- Push the primary package.Mozaic validates the NuGet archive, computes hashes and signature evidence, and records publisher provenance.
- Confirm the version page.Check package hash, signature result, listed state, and provenance rather than relying only on a successful CLI exit.
Success state
The version is explicitly published, not quarantined, listed, and visible in package search. A matching client can restore the same bytes by exact ID and version.
Publish exact build artifacts with provenance.
A pipeline artifact declaration retains files but does not publish them. Add a terminal publish_in_feed step to the job that produced the packages. Identify exactly one feed by ID or slug and use bounded paths that match only .nupkg or .snupkg entries.
- name: Publish packages
publish_in_feed:
feed:
slug: releases
paths:
- artifacts/packages/*.nupkg
- artifacts/packages/*.snupkg
allow_untrusted: false
The publication record links the package to the run, attempt, artifact entry, repository revision, plan hash, and—when applicable—pull request snapshot, check, merge operation, and related work. The provenance also records whether the execution was trusted.
Open Project › Pipelines › run › Published packages and verify each entry. One failed publication does not become successful merely because the job produced an artifact.
Prefer reversible release controls.
- Deprecate
- Add a reason and message while leaving the version restorable.
- Unlist
- Remove the version from search and version discovery. Exact restore remains possible only when the feed explicitly allows unlisted restore.
- Relist
- Return a previously unlisted, available version to normal discovery.
- Purge
- Permanently remove package and symbol bytes while retaining a tombstone so the coordinate and audit history are not silently reused.
Unlist with the NuGet client
dotnet nuget delete Contoso.Widget 1.2.3 \
--source "https://<app-host>/nuget/<feed-id>/v3/index.json" \
--api-key "<lifecycle-token>"
NuGet delete maps to unlisting, not byte deletion. To deprecate, relist, or purge, use the version lifecycle controls in Mozaic. Purge requires fresh authentication, an audit reason, and the exact normalized confirmation package-id@version.
A deprecation reason contains 1-120 characters; its message is limited to 2,048 characters. Purge is not an escape hatch for replacing an incorrectly published version—publish a corrected version whenever possible.
Make external reads explicit.
Understand public-feed gates and the current UI boundary
An existing feed is anonymously readable only when its visibility is Public, it has been explicitly published, and both its organization and project are publicly available. Setting one child resource to Public never overrides a private parent. The current project feed settings list each feed's visibility and unlisted-restore policy, but do not provide a feed publication editor; new feeds are always private. Treat the inventory as evidence, not as a publication workflow.
Configure an upstream
- Add an HTTPS flat-container source.Mozaic accepts public DNS destinations and rejects unsafe loopback, private-network, or credential-bearing URLs.
- Constrain the package pattern.Route an exact ID or one trailing-wildcard prefix instead of mirroring every request by default.
- Set priority and enabled state.Priority controls selection where more than one mapping applies.
- Choose cache-on-error behavior.Serving an already verified cache entry during an upstream error improves availability but can intentionally return older upstream bytes.
Fetched bytes are hashed and cached. If an upstream later returns different bytes for the same package coordinate, Mozaic quarantines the changed result instead of silently replacing trusted cached content.
Design releases inside the registry envelope.
| Boundary | Current behavior |
|---|---|
| Primary package | 512 MiB maximum per .nupkg. |
| Symbol package | 256 MiB maximum per .snupkg or symbols package. |
| Multipart overhead | 1 MiB above the permitted archive size. |
| Versions per package ID | 128 versions in one feed. |
| Collection page size | 1-100 results. |
| Token expiry | 1-8,760 hours in the current creation form (up to 365 days). |
| Token package pattern | 128 characters maximum; one exact ID, *, or one safe prefix ending in a single wildcard. |
| Feed identity | Name 1-120 characters; slug at most 63 lowercase ASCII letters, digits, or internal hyphens. |
- Never put a feed token in source, command output, pipeline logs, package metadata, or a committed
NuGet.config. - Give restore, publication, and lifecycle automation separate tokens so compromise or rotation has a narrow effect.
- Use exact or team-prefix package patterns; reserve
*for deliberately feed-wide clients. - Inspect SHA-256, NuGet SHA-512, signature evidence, provenance, and quarantine state when validating a release.
Resolve common package failures.
The service index returns unauthorized or not found
Copy the URL from the feed page and confirm it contains the feed ID. For a private feed, use an unexpired, unrevoked token with read scope and a package pattern that matches the request. Anonymous access additionally requires all organization, project, feed-visibility, and explicit-publication gates.
Push is forbidden although restore works
Read does not imply push. Check the token's push scope, package-ID pattern, expiry, feed binding, and current owner authorization. Symbols need the separate push-symbols scope.
The package was pushed but search cannot find it
Open the version page. It must be explicitly published, listed, and not quarantined. An unlisted version is intentionally absent from search; a changed upstream digest is quarantined rather than trusted.
An exact restore of an unlisted version fails
Exact restore is available only when Allow exact restore of unlisted versions is enabled for that feed. A purged or quarantined version cannot be restored under that setting.
The version already exists
NuGet coordinates are immutable. Compare the published hash and metadata, then increment the package version and publish again. Do not purge merely to replace bytes at the same coordinate.
A pipeline artifact exists but the package does not
Artifact retention and feed publication are distinct. Add a terminal publish_in_feed step, identify exactly one feed, keep the path within the allowed package extensions, and inspect each Published packages result.