Skip to content

How Cascade works

Cascade turns one manifest into a chain of stages. A change starts on trunk, moves through your environments in order, and crosses a prerelease/release boundary near the top of the chain. Two off-ramps, rollback and hotfix, branch off that line when something needs to move backward or sideways. This page is the map: it names every stage and says when it fires. The getting started tutorial and the task guides fill in the how.

flowchart TD
    trunk["Trunk push<br/>(orchestrate.yaml)"]
    subgraph chain["Environment chain (environments order)"]
      direction TB
      e1["environments[0]<br/>build target"]
      e2["...middle environments..."]
      pre["environments[N-1]<br/>prerelease marker"]
      rel["environments[N]<br/>release marker"]
      e1 --> e2 --> pre --> rel
    end
    trunk --> e1
    promote["Promote<br/>(promote.yaml)"]
    promote -. drives .-> chain
    rollback["Rollback off-ramp<br/>(cascade-rollback.yaml)"]
    hotfix["Hotfix off-ramp<br/>(cascade-hotfix.yaml)"]
    chain --> rollback
    chain --> hotfix
    hotfix -. patched ref .-> chain

The single-environment case collapses this: promote.yaml holds release-workflow content instead of the promote chain, so the one environment publishes directly.

Every push to your trunk branch runs the orchestrate workflow, which builds and deploys the first environment.

  • Manifest field: trunk_branch, with the paths filter from triggers (or the per-callback triggers).
  • Generated file: orchestrate.yaml.
  • Fires on: push to trunk_branch (filtered by triggers) and workflow_dispatch. Optional repository_dispatch, workflow_run, and merge_group triggers come from extra_triggers.

The environments list is the spine of the graph. Its order is the promotion order: a change moves from each environment to the next, one step at a time, carrying the same built artifact forward.

  • Manifest field: environments (an ordered list).
  • Generated file: promote.yaml.
  • Fires on: workflow_dispatch. You pick a promotion target (for example dev-to-uat) and the run advances every environment from the source up to that target.

The boundary is positional, not a named environment. The second-from-top environment is the prerelease marker: promoting into it cuts a prerelease. The top environment is the release marker: promoting into it publishes the final release. For environments: [dev, test, uat, prod], promoting to uat marks a prerelease and promoting to prod publishes the release.

  • Manifest field: position within environments (last = release, second-from-last = prerelease).
  • Generated file: promote.yaml (the same workflow; the boundary is a property of which target you promote to).
  • Fires on: the promote run whose target is the prerelease or release environment.

Rollback moves an environment backward to a previously recorded state. It reads the deploy history Cascade keeps in manifest state.

  • Manifest field: at least two environments; rollback is optional and adds an external trigger.
  • Generated file: cascade-rollback.yaml.
  • Fires on: workflow_dispatch, plus repository_dispatch when rollback.repository_dispatch is set so an external signal can trigger it.

Hotfix patches an environment off a divergent branch instead of trunk, so an urgent fix can ship to one environment without waiting for the full chain. The patched ref rejoins the chain through manifest state.

  • Manifest field: two or more environments (the hotfix workflow is emitted whenever the environment chain can diverge).
  • Generated file: cascade-hotfix.yaml.
  • Fires on: workflow_dispatch, and pull_request (closed) on hotfix branches to finalize the patch.

For the operator-level walkthrough of each, see Run a hotfix and Roll back an environment.

These lanes are opt-in. They guard the graph rather than move artifacts through it, so they sit alongside the chain rather than on it.

LaneManifest fieldGenerated fileFires on
External coordinationexternalexternal-update.yamlworkflow_dispatch, dispatched by a satellite repo after its own deploy
Validate checkvalidate_check.enabledcascade-validate.yamlpull_request
Merge queuemerge_queue.enabledcascade-merge-queue.yamlmerge_group
PR previewpr_preview.enabledcascade-pr-preview.yamlpull_request
Drift checkdrift_check.enabled (drift_check.comment for the companion)cascade-drift-check.yaml, plus cascade-drift-comment.yaml when comment is setpull_request for the check; workflow_run for the comment companion

A primary repo coordinates deploys in other repos through the external lane: when the manifest lists external repos, Cascade emits a receiver workflow that records or runs external updates. PR preview spins up a preview environment for a pull request; see its field in the manifest reference. Drift check fails a pull request when the committed workflows fall out of sync with the manifest.

Every field above is documented in full in the manifest reference, and every generated file’s internal anatomy is in generated workflows reference.

Everything above describes one unit moving through one chain. If a repository holds more than one thing to ship, such as an API and a web frontend, a components: block gives each its own version line, environment ladder, and promotion, hotfix, and rollback history, all from the same trunk and the same manifest. Each component runs the model on this page in its own isolated namespace.

Components are additive: a manifest with no components: block is a single implicit component that spans the whole repository and behaves exactly as described here. See Split a repo into components for the walkthrough.


Prerequisite: Why Cascade. Next: Getting started to build your first pipeline.