Skip to content

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…