Checkpoints in your delivery pipeline and the recipes for deploying changes
A Stage represents an environment (dev, staging, prod) or any logical checkpoint where Freight is deployed and verified.
The Stage requests Freight directly from a Warehouse. Typically used for the first Stage (e.g., dev).
requestedFreight:
- origin:
kind: Warehouse
name: my-warehouse
sources:
direct: true
The Stage only accepts Freight that has been verified in an upstream Stage. Used for staging, prod.
requestedFreight:
- origin:
kind: Warehouse
name: my-warehouse
sources:
stages:
- dev
This ensures no Freight reaches prod without passing through dev and staging first.
A Promotion Template is a list of steps that Kargo executes when promoting Freight to a Stage. Each step is a built-in function.
git-clone — Clone a Git repositorygit-update — Update files with new versions (formerly kustomize-set-image, yaml-update)git-commit — Commit the changesgit-push — Push to remoteargocd-update — Tell ArgoCD to sync1. How does a staging Stage ensure it only receives tested Freight?
2. What is a Promotion Template?
3. Which Stage typically requests Freight directly from a Warehouse?
Most promotions follow this pattern: clone → update → commit → push
git-clonepromotionTemplate:
steps:
- uses: git-clone
config:
repoURL: https://github.com/my-org/k8s-config.git
checkout:
- branch: main
path: ./src
# Output: working directory at ./src
Clones the repository to a temporary working directory. The path defines where subsequent steps can find the files.
git-update - uses: git-update
config:
path: ./src
updates:
# Update image tag in values.yaml
- file: apps/my-web-app/values.yaml
key: image.tag
value: ${{ freight.images["myacr.azurecr.io/my-web-app"].tag }}
# Update chart version
- file: apps/my-web-app/Chart.yaml
key: version
value: ${{ freight.charts["my-app"].version }}
Uses expressions to inject Freight values into your YAML files.
${{ freight.images["registry/repo"].tag }} — Image tag${{ freight.images["registry/repo"].digest }} — Image digest${{ freight.commits["repo-url"].id }} — Git commit SHA${{ freight.charts["chart-name"].version }} — Chart versionThese expressions are evaluated at promotion time using the specific Freight being promoted.
git-commit - uses: git-commit
as: commit
config:
path: ./src
messageFromSteps:
- git-update # auto-generates commit message from changes
# OR custom message:
# message: "chore: promote my-web-app to ${{ ctx.stage }}"
The as: commit alias lets later steps reference the commit output (e.g., the commit SHA).
git-push - uses: git-push
config:
path: ./src
# Push to the same branch (main)
# OR push to an environment-specific branch:
targetBranch: env/dev
env/dev, env/staging, env/prod. ArgoCD watches the environment branch.argocd-update - uses: argocd-update
config:
apps:
- name: my-web-app-dev
sources:
- repoURL: https://github.com/my-org/k8s-config.git
# Update the target revision to the commit we pushed
desiredCommitFromStep: commit
Optionally tells ArgoCD to update the Application's target revision to the exact commit Kargo just pushed. This triggers an immediate sync rather than waiting for ArgoCD polling.
apiVersion: kargo.akuity.io/v1alpha1
kind: Stage
metadata:
name: dev
namespace: my-web-app
spec:
requestedFreight:
- origin:
kind: Warehouse
name: my-warehouse
sources:
direct: true
promotionTemplate:
steps:
- uses: git-clone
config:
repoURL: https://github.com/my-org/k8s-config.git
checkout:
- branch: main
path: ./src
- uses: git-update
config:
path: ./src
updates:
- file: apps/my-web-app/values.yaml
key: image.tag
value: ${{ freight.images["myacr.azurecr.io/my-web-app"].tag }}
- uses: git-commit
as: commit
config:
path: ./src
messageFromSteps:
- git-update
- uses: git-push
config:
path: ./src
1. What is the correct order of Git promotion steps?
2. How do you reference an image tag from Freight in a promotion step?
3. What does the argocd-update step do?
# values.yaml before promotion:
image:
repository: myacr.azurecr.io/my-web-app
tag: "1.4.0" # ← Kargo updates this
replicaCount: 3
# values.yaml after promotion:
image:
repository: myacr.azurecr.io/my-web-app
tag: "1.5.0" # ← Updated by git-update step
replicaCount: 3 # untouched
The git-update step surgically modifies only the specified keys.
The real power: dev → staging → prod
apiVersion: kargo.akuity.io/v1alpha1
kind: Stage
metadata:
name: staging
namespace: my-web-app
spec:
requestedFreight:
- origin:
kind: Warehouse
name: my-warehouse
sources:
stages:
- dev # Only accept Freight verified in dev
promotionTemplate:
steps:
- uses: git-clone
config:
repoURL: https://github.com/my-org/k8s-config.git
checkout:
- branch: main
path: ./src
- uses: git-update
config:
path: ./src
updates:
- file: apps/my-web-app/staging-values.yaml
key: image.tag
value: ${{ freight.images["myacr.azurecr.io/my-web-app"].tag }}
- uses: git-commit
as: commit
config:
path: ./src
messageFromSteps: [git-update]
- uses: git-push
config:
path: ./src
Freight is promoted automatically when it becomes available. No human intervention.
# In the Project spec:
promotionPolicies:
- stage: dev
autoPromotionEnabled: true
Best for: dev, feature environments
Someone must explicitly trigger the promotion via UI or CLI.
# In the Project spec:
promotionPolicies:
- stage: prod
autoPromotionEnabled: false
Best for: staging, production
# Via CLI
kargo promote --project my-web-app \
--stage staging \
--freight jolly-penguin
# Via kubectl (create a Promotion resource)
apiVersion: kargo.akuity.io/v1alpha1
kind: Promotion
metadata:
name: promote-staging-abc123
namespace: my-web-app
spec:
stage: staging
freight: abc123def456 # Freight name or alias
# Via UI: drag Freight onto the Stage!
# Check promotion status
kargo get promotions --project my-web-app
# NAME STAGE FREIGHT STATUS
# promote-staging-abc123 staging jolly-penguin Succeeded
# promote-dev-abc123 dev jolly-penguin Succeeded
# Detailed view
kargo get promotion promote-staging-abc123 \
--project my-web-app -o yaml
Statuses: Pending Running Succeeded Failed Aborted
For sensitive Stages (production), you can require Freight to be explicitly approved before promotion.
# Approve Freight for the prod Stage
kargo approve --project my-web-app \
--stage prod \
--freight jolly-penguin
1. In a dev → staging → prod pipeline, what does staging's requestedFreight look like?
2. Where is auto-promotion configured?
3. How can you manually approve Freight for a Stage?
Instead of one main branch, use separate branches for each environment:
env/dev — ArgoCD dev Application watches this branchenv/staging — ArgoCD staging Application watches this branchenv/prod — ArgoCD prod Application watches this branch# In the dev Stage's git-push step:
- uses: git-push
config:
path: ./src
targetBranch: env/dev
Use a single branch with directories per environment:
k8s-config/
apps/my-web-app/
dev/
values.yaml # image.tag: 1.5.0
staging/
values.yaml # image.tag: 1.4.0
prod/
values.yaml # image.tag: 1.3.0
Chart.yaml
Each Stage's git-update step targets the corresponding directory.
When dev, staging, and prod share similar promotion logic, you can use:
${{ ctx.stage }} to dynamically select paths# Dynamic path using context
- uses: git-update
config:
path: ./src
updates:
- file: apps/my-web-app/${{ ctx.stage }}/values.yaml
key: image.tag
value: ${{ freight.images["myacr.azurecr.io/my-web-app"].tag }}
A Stage can request Freight from multiple Warehouses. Each origin provides different artifact types.
spec:
requestedFreight:
- origin:
kind: Warehouse
name: app-images # container images
sources:
direct: true
- origin:
kind: Warehouse
name: config-repo # Git config changes
sources:
direct: true
Useful when images and config are managed separately.
1. What does ${{ ctx.stage }} evaluate to in a promotion step?
2. In the environment branches pattern, what does each ArgoCD Application watch?
3. Can a Stage request Freight from multiple Warehouses?
${{ freight.images[...].tag }} inject Freight values into stepsModule 04: Verification & Advanced Patterns
Trust but verify. AnalysisTemplates, parallel stages, rollbacks, and more.