Publish¶
publish: declares what StageFreight does with a build — push image tags, sync project
identity, publish a GitLab component, cut a forge release, publish an archive or package, or
deploy a static site. It's an id → target map; each entry is a discriminated union keyed
by kind — the kind decides which other keys are valid.
Every target shares a when: routing block (all non-empty conditions must match — AND
logic; see Patterns & conditions). The map key is the
target's id.
Registry — push image tags¶
Pushes a build's image to a container registry under one or more tags:.
publish:
dockerhub-stable:
kind: registry
build: myapp # references a builds[] id
registry: dockerhub # references a registries[] id — url/provider/creds/path resolve from it
tags: ["{version}", "{major}.{minor}", "latest"]
when:
git_tags: [stable] # a named pattern from git.tags:
events: [tag]
retention: { keep_last: 10, keep_monthly: 6 }
registry: references a registries[] id (see Identity & Connectivity); pass a
list (registry: [dockerhub, ghcr, harbor]) to fan the target across several registries at
once. tags template expansion and retention are cross-cutting — see Concepts.
Project Metadata — sync identity to registries & forge repos¶
kind: metadata pushes a project's identity — description, long readme/overview, website,
topics, logo — to every registry and forge repo destination that can hold it, from one
source of truth. Each field maps to what a destination supports and is silently skipped where
absent; nothing is truncated, and org/namespace fields are never touched.
publish:
project-meta:
kind: metadata
registry: [dockerhub, harbor] # registry pages
repos: [github-mirror, primary] # forge project pages
description: # length-tiered variants — the engine fits each destination's cap
- "The full, richest tagline your most generous destination can hold…"
- "A trimmer version for tighter caps…"
- "A punchy fallback that fits anywhere"
readme: README.md # long markdown body (registries with an overview field)
website: https://example.com # external site URL (forges that have the field)
topics: [ci-cd, gitops, kubernetes] # discovery tags (forges) — normalized to lowercase-hyphenated
logo: assets/logo.png # project avatar (project-scoped forge avatars)
when: { branches: [main], events: [push, tag] }
What each destination supports¶
| destination | description (short) | readme (long body) | website | topics | logo |
|---|---|---|---|---|---|
| Docker Hub | ✓ ~100 (word-truncated) | ✓ Overview (~25k) | ✕ | ✕ | ✕ (org-scoped) |
| Harbor | — (single field) | ✓ Info (markdown) | ✕ | ✕ | ✕ |
| Quay | — (single field) | ✓ Description (markdown) | ✕ | ✕ | ✕ |
| JFrog | ✓ config description | ✕ (no README API) | ✕ | ✕ | ✕ |
| GHCR / GitLab CR | ✕ (no description API) | ✕ | ✕ | ✕ | ✕ |
| GitHub | ✓ ~350 | ✕ (README is committed) | ✓ | ✓ | ✕ (org-scoped) |
| GitLab | ✓ | ✕ (committed) | ✕ (no field) | ✓ | ✓ project avatar |
| Gitea / Forgejo | ✓ | ✕ (committed) | ✓ | ✓ | ✓ project avatar |
Behavior: single-field registries (Harbor, Quay) take the readme in their one markdown
field (falling back to the short description if no readme); the engine fits the longest
description variant to each destination's cap and warns rather than truncating; logo
syncs idempotently (re-uploads only on change) and is skipped where the avatar is
org-scoped. Each run reports per-destination what was set / skipped / warned.
Release — cut forge releases¶
Creates a release on the detected forge, with rolling git-tag aliases that track it.
publish:
primary-release:
kind: release
aliases: ["{version}", "{major}.{minor}", "latest"]
retention: { keep_last: 10, keep_monthly: 6 }
when: { git_tags: [stable], events: [tag] }
The aliases are rolling git tags resolved with the same template
variables as everything else — {version} → 1.2.3,
{major}.{minor} → 1.2, latest → always the newest.
CLI
Release authoring (release create, release notes, release prune, release badge)
and its flags live in the CLI Reference. In CI these run as part of
the publish phase; you rarely invoke them by hand.
Other target kinds¶
gitlab-component (GitLab CI/CD component publish), archive / package
distribution (kind: generic-package), and pages (static-site
deploy, e.g. these docs to Cloudflare Pages) are declared the same way — a kind, a build:
or source, and a when:. Their full field sets are in the generated reference below.
Reference¶
The blocks below are generated from the config source — for each kind, exactly the fields it accepts, with each field's meaning, allowed values, and whether it's required.
publish¶
Targets defines distribution targets and side-effects. Declared under the publish: key as an id→target map (execution order preserved). The retired list form (targets:) no longer parses — upgrade via the config migrator.
kind: registry¶
publish:
- id: <string> # ID is the unique identifier for this target (logging, status, enable/disable). · required
kind: registry # Kind is the target type. Determines which fields are valid. · required
registry: [<string>] # Registry references registries[].id for registry/metadata targets. Accepts a single id (registry…
build: <string> # Build references a BuildConfig.ID. Required for kind: registry.
tags: [<string>] # Tags are tag templates resolved against version info (kind: registry). e.g., ["{version}"…
signing_profile: <string> # SigningProfile references a signing.profiles[].id — the trust profile this target signs under.…
native_scan: false # NativeScan enables post-push vulnerability scanning via the registry's own built-in scanner.…
retention: # Retention controls cleanup of old tags/releases. Structured only in v2 (no scalar shorthand).
keep_last: <int> # keep the N most recent tags per series (0/-1/unset = ∞) · required
keep_daily: <int> # keep one per day for the last N days · required
keep_weekly: <int> # keep one per week for the last N weeks · required
keep_monthly: <int> # keep one per month for the last N months · required
keep_yearly: <int> # keep one per year for the last N years · required
keep_branches: <int> # keep the N most-recent identity groups per template (bounds retired branches; 0/unset = ∞) · required
identity: [<string>] # extra identity vars beyond the {branch}/{env} defaults — partition tags into independent series · required
protect: [<string>] # tag patterns that are never deleted, an explicit override · required
when: # When specifies routing conditions for this target: a single condition-set, or a list of them (OR…
- branches: [<string>] # Branches lists branch filters. Each entry is a policy name or "re:<regex>". Empty = no branch…
git_tags: [<string>] # GitTags lists git tag filters. Each entry is a policy name or "re:<regex>". Empty = no tag…
events: [<string>] # Events lists CI event type filters. Supported: push, tag, release, schedule, manual, pull_request…
forges: [<string>] # Forges restricts this target to specific CI forges by provider name (github, gitlab, gitea…
outcomes: [<string>] # Outcomes gates on the RUN outcome (success | failure | warning) — the notification dimension of…
kind: metadata¶
publish:
- id: <string> # ID is the unique identifier for this target (logging, status, enable/disable). · required
kind: metadata # Kind is the target type. Determines which fields are valid. · required
registry: [<string>] # Registry references registries[].id for registry/metadata targets. Accepts a single id (registry…
repos: [<string>] # Repos names the destination repos[].id for a kind: release target. The repo with role primary is…
description: [<string>] # Description is the short project description/tagline. A scalar for kind: registry; kind: metadata…
readme: <string> # Readme is the long markdown 'project page' body (registries only: Docker Hub Overview, Harbor Info…
website: <string> # Website is the project's external site URL (forges: GitHub, Gitea/Forgejo).
topics: [<string>] # Topics are discovery tags (forges: GitHub, GitLab, Gitea). Authored freely; the engine normalizes…
logo: <string> # Logo is a path to the project avatar image (project-scoped forges: GitLab, Gitea/Forgejo); synced…
when: # When specifies routing conditions for this target: a single condition-set, or a list of them (OR…
- branches: [<string>] # Branches lists branch filters. Each entry is a policy name or "re:<regex>". Empty = no branch…
git_tags: [<string>] # GitTags lists git tag filters. Each entry is a policy name or "re:<regex>". Empty = no tag…
events: [<string>] # Events lists CI event type filters. Supported: push, tag, release, schedule, manual, pull_request…
forges: [<string>] # Forges restricts this target to specific CI forges by provider name (github, gitlab, gitea…
outcomes: [<string>] # Outcomes gates on the RUN outcome (success | failure | warning) — the notification dimension of…
kind: gitlab-component¶
publish:
- id: <string> # ID is the unique identifier for this target (logging, status, enable/disable). · required
kind: gitlab-component # Kind is the target type. Determines which fields are valid. · required
spec_files: [<string>] # SpecFiles lists component spec file paths (kind: gitlab-component).
catalog: false # Catalog enables GitLab Catalog registration (kind: gitlab-component).
when: # When specifies routing conditions for this target: a single condition-set, or a list of them (OR…
- branches: [<string>] # Branches lists branch filters. Each entry is a policy name or "re:<regex>". Empty = no branch…
git_tags: [<string>] # GitTags lists git tag filters. Each entry is a policy name or "re:<regex>". Empty = no tag…
events: [<string>] # Events lists CI event type filters. Supported: push, tag, release, schedule, manual, pull_request…
forges: [<string>] # Forges restricts this target to specific CI forges by provider name (github, gitlab, gitea…
outcomes: [<string>] # Outcomes gates on the RUN outcome (success | failure | warning) — the notification dimension of…
kind: release¶
publish:
- id: <string> # ID is the unique identifier for this target (logging, status, enable/disable). · required
kind: release # Kind is the target type. Determines which fields are valid. · required
aliases: [<string>] # Aliases are rolling git tag aliases (kind: release). e.g., ["{version}", "{major}.{minor}"…
tag: <string> # Tag is the immutable identity pattern for a release channel (kind: release). Distinct from Aliases…
archives: <string> # Archives references a binary-archive target ID (kind: release and generic-package).
prerelease: false # Prerelease marks the forge release as a pre-release (kind: release). DEPRECATED: prefer `type…
signing_profile: <string> # SigningProfile references a signing.profiles[].id — the trust profile this target signs under.…
retention: # Retention controls cleanup of old tags/releases. Structured only in v2 (no scalar shorthand).
keep_last: <int> # keep the N most recent tags per series (0/-1/unset = ∞) · required
keep_daily: <int> # keep one per day for the last N days · required
keep_weekly: <int> # keep one per week for the last N weeks · required
keep_monthly: <int> # keep one per month for the last N months · required
keep_yearly: <int> # keep one per year for the last N years · required
keep_branches: <int> # keep the N most-recent identity groups per template (bounds retired branches; 0/unset = ∞) · required
identity: [<string>] # extra identity vars beyond the {branch}/{env} defaults — partition tags into independent series · required
protect: [<string>] # tag patterns that are never deleted, an explicit override · required
when: # When specifies routing conditions for this target: a single condition-set, or a list of them (OR…
- branches: [<string>] # Branches lists branch filters. Each entry is a policy name or "re:<regex>". Empty = no branch…
git_tags: [<string>] # GitTags lists git tag filters. Each entry is a policy name or "re:<regex>". Empty = no tag…
events: [<string>] # Events lists CI event type filters. Supported: push, tag, release, schedule, manual, pull_request…
forges: [<string>] # Forges restricts this target to specific CI forges by provider name (github, gitlab, gitea…
outcomes: [<string>] # Outcomes gates on the RUN outcome (success | failure | warning) — the notification dimension of…
kind: binary-archive¶
publish:
- id: <string> # ID is the unique identifier for this target (logging, status, enable/disable). · required
kind: binary-archive # Kind is the target type. Determines which fields are valid. · required
build: <string> # Build references a BuildConfig.ID. Required for kind: registry.
name: <string> # Name is the archive filename template (kind: binary-archive). Supports: {id}, {version}, {os}…
format: <string> # Format is the archive format: "tar.gz", "zip", "auto", or "binary" (kind: binary-archive). "auto"…
binary_name: <string> # BinaryName overrides the binary name inside the archive (kind: binary-archive). Auto-detected from…
include: [<string>] # Include lists extra files to bundle into the archive (kind: binary-archive). e.g., ["README.md"…
checksums: false # Checksums generates a SHA256SUMS file alongside archives (kind: binary-archive).
when: # When specifies routing conditions for this target: a single condition-set, or a list of them (OR…
- branches: [<string>] # Branches lists branch filters. Each entry is a policy name or "re:<regex>". Empty = no branch…
git_tags: [<string>] # GitTags lists git tag filters. Each entry is a policy name or "re:<regex>". Empty = no tag…
events: [<string>] # Events lists CI event type filters. Supported: push, tag, release, schedule, manual, pull_request…
forges: [<string>] # Forges restricts this target to specific CI forges by provider name (github, gitlab, gitea…
outcomes: [<string>] # Outcomes gates on the RUN outcome (success | failure | warning) — the notification dimension of…
kind: generic-package¶
publish:
- id: <string> # ID is the unique identifier for this target (logging, status, enable/disable). · required
kind: generic-package # Kind is the target type. Determines which fields are valid. · required
repo: <string> # Repo references a repos[].id (kind: generic-package). The forge identity (provider, url, project…
package: <string> # Package is the generic package name (kind: generic-package). Defaults to the repo project's…
version: <string> # Version is the immutable package version pattern (kind: generic-package). Resolved against version…
archives: <string> # Archives references a binary-archive target ID (kind: release and generic-package).
when: # When specifies routing conditions for this target: a single condition-set, or a list of them (OR…
- branches: [<string>] # Branches lists branch filters. Each entry is a policy name or "re:<regex>". Empty = no branch…
git_tags: [<string>] # GitTags lists git tag filters. Each entry is a policy name or "re:<regex>". Empty = no tag…
events: [<string>] # Events lists CI event type filters. Supported: push, tag, release, schedule, manual, pull_request…
forges: [<string>] # Forges restricts this target to specific CI forges by provider name (github, gitlab, gitea…
outcomes: [<string>] # Outcomes gates on the RUN outcome (success | failure | warning) — the notification dimension of…
kind: pages¶
publish:
- id: <string> # ID is the unique identifier for this target (logging, status, enable/disable). · required
kind: pages # Kind is the target type. Determines which fields are valid. · required
provider: <string> # Provider is the vendor type for auth and API behavior. Registry: docker, ghcr, gitlab, jfrog… · one of: cloudflare, github
build: <string> # Build references a BuildConfig.ID. Required for kind: registry.
dir: <string> # Dir publishes a repo directory directly instead of a build's output tree (kind: pages). Exactly one…
domain: [<string>] # Domain is the custom domain(s) (kind: pages). Accepts a bare scalar or a list:
project: <string> # Project is the Cloudflare Pages project name (provider: cloudflare). Default: the target id.…
base_path: <string> # BasePath is the URL path the site is served under (kind: pages). Inferred per provider (Cloudflare…
exclude: [<string>] # Exclude drops matching paths from the publish workspace before deploy (kind: pages). Globs, applied…
when: # When specifies routing conditions for this target: a single condition-set, or a list of them (OR…
- branches: [<string>] # Branches lists branch filters. Each entry is a policy name or "re:<regex>". Empty = no branch…
git_tags: [<string>] # GitTags lists git tag filters. Each entry is a policy name or "re:<regex>". Empty = no tag…
events: [<string>] # Events lists CI event type filters. Supported: push, tag, release, schedule, manual, pull_request…
forges: [<string>] # Forges restricts this target to specific CI forges by provider name (github, gitlab, gitea…
outcomes: [<string>] # Outcomes gates on the RUN outcome (success | failure | warning) — the notification dimension of…