Buildkite Certification

Learn · Dynamic pipelines

Uploading steps at build time

A pipeline file is a starting point, not the whole build. A running step can generate more steps and hand them back.

steps:
  - label: ":pipeline: Generate"
    command: .buildkite/generate.sh | buildkite-agent pipeline upload

.buildkite/generate.sh writes pipeline YAML to standard output. buildkite-agent pipeline upload reads YAML from standard input and adds those steps to the build that is currently running. They start immediately.

The script can be anything that emits YAML — a shell script, a Ruby program, a Go binary. It runs on an agent with your repository checked out, so it can look at the actual state of the code:

#!/usr/bin/env bash
set -euo pipefail

echo "steps:"
for service in $(git diff --name-only origin/main | cut -d/ -f1 | sort -u); do
  echo "  - label: \":hammer: $service\""
  echo "    command: make -C $service test"
done

That pipeline only tests what changed. On a monorepo, this is usually the single largest saving available.

Why upload rather than write a file

You might wonder why the generated YAML is piped to the agent instead of written to pipeline.yml. Because the build is already running — it read its configuration when it started. Uploading is how you add steps to a build in flight, and it can happen as many times as you like, from as many steps as you like.

Check

Write a pipeline containing exactly one command step, labelled ":pipeline: Generate", that runs `.buildkite/generate.sh` and pipes its output into the agent so the generated steps join the running build.

Sign in to answer and record your progress.