Skip to content
Publishing your own catalog

Publishing your own catalog

nem catalog publish turns a directory of package manifests into an OCI index that other machines can add. It pushes manifests, not archives; those come from build --push and fill.

What publish does

nem catalog publish takes a bare repository reference and a local catalog, a directory or a single pkg.yaml:

nem catalog publish registry.example/nem/catalog . --dry-run   # the plan, nothing pushed
nem catalog publish registry.example/nem/catalog .             # publish under tag v4

It lints the catalog first and refuses on findings. Both runs start by comparing the catalog with the index the tags currently point at. The dry run prints the packages that would change, as new, updated or removed, and the tags it would write:

PACKAGE  VERSION  STATUS
jq       1.8.2    new
OK Would publish registry.example/nem/catalog: 1 to push, tags v4, v4.20260930T092433Z

The real run pushes each changed package manifest, assembles the index, and tags it:

OK Compared with registry.example/nem/catalog:v4: 1 to push
OK Pushed jq 1.8.2
OK Published registry.example/nem/catalog: 1 pushed, 0 unchanged, tags v4, v4.20260930T092433Z

Two things to notice. The reference carries no tag: --tag says which tags to move, v4 by default, and the reference with a tag is refused with must be a bare repository ref. And every run also writes a release tag, v4. followed by the UTC time, so each published state keeps a name you can pin or roll back to. A second run with nothing changed pushes nothing and moves the tags to the same index:

OK Compared with registry.example/nem/catalog:v4: 1 unchanged
OK Published registry.example/nem/catalog: 0 pushed, 1 unchanged, tags v4, v4.20260930T092512Z

A package that the published index lists but the catalog no longer has is dropped from the new index; the dry run shows it as removed and the summary counts it.

--force pushes every manifest again regardless.

--output json prints the result on stdout for scripts: the reference, the tags, the digest of the published index, and the changed packages. The dry run prints the same document, with the digest the publish would produce, so a pipeline can tag that exact index later.

{
  "ref": "registry.example/nem/catalog",
  "tags": ["v4", "v4.20260930T092433Z"],
  "index": "sha256:…",
  "packages": [{"name": "jq", "version": "1.8.2", "status": "new"}]
}

Archives

Publishing pushes manifests, not archives. Packages built from source get their archives from nem catalog build --push against the published reference with its tag; see Building from source. Packages that download from upstream work without archives, and nem catalog fill against the published reference adds them when you want consumers to stop reaching upstream.

A safe pipeline

The official catalog publishes to a staging tag, proves it, then promotes, and the same shape works for any catalog:

nem catalog publish registry.example/nem/catalog . --tag v4-staging     # 1. stage
nem catalog build registry.example/nem/catalog:v4-staging --missing --push   # 2. archives against staging
nem catalog test registry.example/nem/catalog:v4-staging --package jq   # 3. prove it, on each platform's runner
oras tag registry.example/nem/catalog:v4-staging v4                     # 4. promote by retagging

Promotion retags the same index, so what was tested is what ships. The release tag written in step 1 is the permanent name for that state.

Telling consumers

nem catalog add corp registry.example/nem/catalog:v4           # follow the moving tag
nem catalog add corp registry.example/nem/catalog@sha256:…     # or freeze one state

Access and rollout covers credentials and getting the entry onto every machine.

Related