Command step
A command step runs one or more shell commands on one or more agents.
Each command step can run either a shell command like npm test, or an executable file, or script like build.sh.
A command step can be defined in your pipeline settings, or in your pipeline.yml file.
steps:
- command: "tests.sh"
To have a set of commands execute sequentially in a single step, use the command syntax followed by a | symbol:
steps:
- command: |
"tests.sh"
"echo 'running tests'"
You can also define multiple commands by using the commands syntax and starting each new command on a new line:
steps:
- commands:
- "tests.sh"
- "echo 'running tests'"
When running multiple commands, either defined in a single line (npm install && tests.sh) or defined in a list, any failure will prevent subsequent commands from running, and will mark the command step as failed.
The results of running the commands defined in separate command steps are not guaranteed to be available to the subsequent command steps as those steps could be running on a different machine in the cluster queue.
The shell command(s) provided for execution must be resolvable through the directories defined within the PATH environment variable. When referencing scripts for execution, prefer using a relative path (for example, ./scripts/build.sh, or scripts/bin/build-prod).
Command step attributes
Required attributes:
command |
The shell command/s to run during this step. This can be a single line of commands, or a list of commands that must all pass. Example: "build.sh"Example: - "npm install"- "./tests.sh"Alias: commands
|
steps:
- commands:
- "npm install && npm test"
- "extras/moretests.sh"
- "./build.sh"
Pipelines without command steps
Although the command attribute is required for a command step, some plugins work without a command step, so it isn't strictly necessary for your pipeline to have an explicit command step.
Optional attributes:
agents |
A map of agent tag keys to values to target specific agents for this step. Example: npm: "true"Alias: agent_query_rules
|
allow_dependency_failure |
Whether to continue to run this step if any of the steps named in the depends_on attribute fail.Default: false
|
artifact_paths |
The glob path or paths of artifacts to upload from this step. This can be a single line of paths separated by semicolons, or a list. Example: "logs/**/*;coverage/**/*"Example: - "logs/**/*"- "coverage/**/*"Alias: artifacts
|
branches |
The branch pattern defining which branches will include this step in their builds. Example: "main stable/*"
|
cancel_on_build_failing |
Setting this attribute to true cancels the job as soon as the build is marked as failing.Default: "false"
|
checkout |
A map of git checkout configuration options for this step. See Checkout attributes for available keys. Example: submodules: false
|
concurrency |
A map of concurrency settings: limit, group, method, and cancel_in_progress. Controls the maximum number of jobs allowed to run at the same time. Also accepts an integer with top-level group and method attributes, or null to disable concurrency. See Concurrency attributes.
|
concurrency_group |
Supported top-level alternative to group in the concurrency map. Use the map for new configurations.
|
concurrency_method |
Supported top-level alternative to method in the concurrency map. Accepts ordered (the default) or eager. Use the map for new configurations.
|
depends_on |
A list of step keys that this step depends on. This step will only run after the named steps have completed. See managing step dependencies for more information. Example: "test-suite"
|
env |
A map of environment variables for this step. Example: RAILS_ENV: "test"
|
secrets |
Either an array of Buildkite secrets or a map of environment variables names to Buildkite secrets for this step. Example: - API_ACCESS_TOKEN
|
if |
A boolean expression that omits the step when false. See Using conditionals for supported expressions. Example: build.message != "skip me"
|
key |
A unique string to identify the command step. The value is available in the BUILDKITE_STEP_KEY environment variable.Keys can not have the same pattern as a UUID ( xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx).Example: "linter"Aliases: identifier, id
|
label |
The label that will be displayed in the pipeline visualization in Buildkite. Supports emoji. Example: ":hammer: Tests" will be rendered as "🔨 Tests"Alias: name
|
matrix |
Either an array of values to be used in the matrix expansion, or a single setup key, and an optional adjustments key.steps:
|
parallelism |
The number of parallel jobs that will be created based on this step. Example: 3
|
plugins |
An array of plugins for this step. Example: - docker-compose#v1.0.0:For a step that only needs one plugin, you may use the singular plugin attribute for convenience.
|
priority |
Adjust the priority for a specific job, as a positive or negative integer. Example: - command: "will-run-first.sh"
|
retry |
The conditions for retrying this step. Available types: automatic, manualFor detailed configuration options, see Retry. |
skip |
Whether to skip this step or not. Passing a string (with a 70-character limit) provides a reason for skipping this command. Passing an empty string is equivalent to false.
On the modern build page, reveal skipped steps using Show skipped steps. In the Canvas view, a badge beside the eye icon on the Show skipped steps or Hide skipped steps control shows the skipped step count. Hover over a skipped step to see the reason, or select a skipped command step to see the reason in the step panel. See Viewing why a step was skipped.Example: trueExample: falseExample: "My reason"
|
soft_fail |
Allow specified non-zero exit statuses not to fail the build.
Can be either true to make all exit statuses soft-fail or an array of allowed soft failure exit statuses with the exit_status attribute. Use exit_status: "*" to allow all non-zero exit statuses not to fail the build.Example: trueExample: - exit_status: 1Example: - exit_status: "*"See Soft fail for more details. |
timeout_in_minutes |
The maximum number of minutes a job created from this step is allowed to run. If the job exceeds this time limit, it automatically times out. A job that times out with an exit status of You can also set default and maximum timeouts in the Buildkite UI, or update a job's timeout dynamically while it is running. Example: |
When signed pipelines are enabled, command steps also include a signature object with fields such as value, version, hashing_algorithm, and signed_attributes. This object is computed by the agent during pipeline upload and is not user-configurable.
Agent-applied attributes
These attributes are only applied by the Buildkite agent when uploading a pipeline (buildkite-agent pipeline upload), since they require direct access to your code or repository to process correctly.
Agent-applied attributes are not accepted in pipelines set using the Buildkite interface.
if_changed
if_changed |
A glob pattern that omits the step from a build if it does not match any files changed in the build. Example: "{**.go,go.mod,go.sum,fixtures/**}"From version 3.109.0 of the Buildkite agent, if_changed also supports lists of glob patterns and include and exclude attributes.Minimum Buildkite agent versions: 3.99 (with --apply-if-changed flag), 3.103.0 (enabled by default), 3.109.0 (expanded syntax)
|
For an example pipeline, demonstrating various forms of if_changed, see Using if_changed.
Container image attributes
The image attribute can be used with either the Agent Stack for Kubernetes controller to run your Buildkite agents, or Buildkite hosted agents.
If you are running your Buildkite agents using the Agent Stack for Kubernetes, you can use the
imageattribute to specify a container image for a command step to run its job in.If you are using Buildkite hosted agents, support for the
imageattribute is experimental and subject to change.
image |
A fully qualified image reference string. The Agent Stack for Kubernetes controller will configure the custom image for the command container of this job. The value is available in the BUILDKITE_IMAGE environment variable.Example: "alpine:latest"
|
Support for this image attribute is currently experimental.
Example pipeline, showing how build and step level image attributes interact:
image: "ubuntu:22.04" # The default image for the pipeline's build
steps:
- name: ":node: Frontend tests"
command: |
cd frontend
npm ci
npm test
image: "node:18" # This step's job uses the node:18 image
- name: ":golang: Backend tests"
command: |
cd backend
go mod download
go test ./...
image: "golang:1.21" # This step's job uses the golang:1.21 image
- name: ":package: Package application"
command: |
apt-get update && apt-get install -y zip
zip -r app.zip frontend/ backend/
# No image specified in this step.
# Therefore, this step's job uses the pipeline's default ubuntu:22.04 image
Checkout attributes
Checkout configuration reference
For detailed guidance on configuring checkout, including use cases, security considerations, and troubleshooting, see Git checkout.
The checkout block controls the git checkout behavior for a command step. You can set it at the pipeline level as a default for all steps, or override it per step.
checkout:
submodules: false # pipeline-level default
steps:
- command: "test.sh"
checkout:
depth: 50 # overrides pipeline default for this step
When both a pipeline-level and step-level checkout block are present, each key is resolved independently. The step value takes precedence for any key it sets, and the pipeline value is inherited for any key the step leaves unset.
For flags, commit_verification, and sparse, an explicit entry in the step's env map takes precedence if it sets the same environment variable. For skip, submodules, lfs, and depth, the checkout value always takes effect.
The agent's --no-git-submodules flag retains a hard veto over checkout.submodules. If an agent starts with that flag, it forces BUILDKITE_GIT_SUBMODULES=false regardless of the value emitted by the pipeline, and the build log emits a protected-environment-variable notice.
skip |
Whether the agent should skip the git checkout phase entirely for this step. Accepts a boolean (true or false) or the equivalent string ("true" or "false"). Emitted as BUILDKITE_SKIP_CHECKOUT.Example: true
|
submodules |
Whether the agent should fetch git submodules for this step. Accepts a boolean (true or false) or the equivalent string ("true" or "false"). Emitted as BUILDKITE_GIT_SUBMODULES. When omitted at both the pipeline and step level, the agent uses its own default (true).Example: false
|
lfs |
Whether the agent should download Git LFS objects during checkout. Accepts a boolean (true or false) or the equivalent string ("true" or "false"). Emitted as BUILDKITE_GIT_LFS_ENABLED. When omitted at both the pipeline and step level, the agent uses its own default (false).Example: true
|
depth |
A shallow-clone depth as a positive integer. Appends --depth=N to both BUILDKITE_GIT_CLONE_FLAGS and BUILDKITE_GIT_FETCH_FLAGS.Example: 50
|
flags |
A map of git operation names to flag strings. Each key sets the corresponding BUILDKITE_GIT_*_FLAGS environment variable. When pipeline-level and step-level flags are both present, step-level values win per key and pipeline-level values are inherited for any key the step omits. Valid keys: clone, fetch, checkout, clean.Example: clone: "--filter=blob:none"fetch: "--prune"
|
sparse |
A map that enables git sparse checkout, populating only the listed paths in the working directory. Contains a single key, paths, which accepts a string or a list of strings. Emitted as BUILDKITE_GIT_SPARSE_CHECKOUT_PATHS. Requires git 2.26 or later; the agent falls back to a full checkout on older git versions. Submodules are not initialized when sparse checkout is enabled.Example: paths:
|
ssh_secret |
The key of a Buildkite secret containing an SSH private key to use when cloning the repository. The secret value is fetched at job startup and set as BUILDKITE_GIT_SSH_KEY in the job environment. The agent uses this to configure GIT_SSH_COMMAND for the git checkout.Unlike the other checkout keys, ssh_secret is step-level only. It is not inherited from a pipeline-level checkout block, so it must be set on each step that needs it.The value must be a string that starts with a letter and contains only letters, numbers, and underscores. It cannot start with buildkite or bk.Example: DEPLOY_KEY
|
commit_verification |
Whether the agent should verify that the commit being built exists on the specified branch. For Buildkite agent v4, set the value to For Buildkite agent v3, use v3.136.0 or later for commit verification. In addition to If the agent cannot complete the check (for example, due to a shallow clone that cannot be deepened), it warns and continues, even in In strict
|
steps:
- command: "test.sh"
checkout:
submodules: false
depth: 50
flags:
clone: "--filter=blob:none"
fetch: "--prune"
sparse:
paths:
- .buildkite/
- src/
To clone a private repository using an SSH key stored as a Buildkite secret:
steps:
- command: "make build"
checkout:
ssh_secret: "DEPLOY_KEY"
Matrix attributes
setup |
A list of dimensions, each containing an array of elements. The job matrix is built by combining all values of each dimension, with the other elements of each dimension. |
adjustments |
An array of with keys, each mapping an element to each dimension listed in the array.setup, as well as the attribute to modify for that combination.Currently, only soft_fail and skip can be modified.
|
steps:
- label: "💥 Matrix build with adjustments"
command: "echo {{matrix.os}} {{matrix.arch}} {{matrix.test}}"
matrix:
setup:
arch:
- "amd64"
- "arm64"
os:
- "windows"
- "linux"
test:
- "A"
- "B"
adjustments:
- with:
os: "windows"
arch: "arm64"
test: "B"
soft_fail: true
- with:
os: "linux"
arch: "arm64"
test: "B"
skip: true
Fast-fail running jobs
To automatically cancel any remaining jobs as soon as any job in the build fails (except jobs marked as soft_fail), add the cancel_on_build_failing: true attribute to your command steps.
When a job fails, the build enters a failing state. Other jobs with cancel_on_build_failing: true are automatically canceled, including jobs that are already running and jobs that are still waiting to start. Waiting jobs can include jobs whose dependencies are incomplete or that are blocked by a concurrency limit. After all remaining jobs have finished or been canceled, the build is marked as failed due to the initial job failure.
Jobs can also make the build enter failing before they finish by using promise job failure. When a running job declares a promised hard failure, other running jobs with cancel_on_build_failing: true can be canceled before the declaring job exits.
Concurrency attributes
Use the concurrency map to set a limit, group name, and scheduling method together:
steps:
- command: "deploy.sh"
concurrency:
limit: 1
group: "my-app/deploy"
method: ordered
The map accepts the following attributes:
| Attribute | Description |
|---|---|
limit |
The maximum number of jobs allowed to run at the same time. A positive limit requires a nonempty group name. Omitting the limit or setting it to null disables concurrency. Zero retains the same behavior as integer concurrency: 0; it is not equivalent to null. |
group |
The concurrency group name. Jobs with the same name share a group across pipelines in the organization. Accepts a string or null. |
method |
The scheduling method: ordered (the default) or eager. Use eager to let ready jobs run without waiting for earlier jobs that are not ready. A value of null selects the default method. |
cancel_in_progress |
When true, a job waiting for this concurrency group asks Buildkite Pipelines to cancel blocking jobs in the same group, instead of waiting for them to finish naturally. Cancellation is asynchronous and does not guarantee that only the latest job runs. Requires a positive limit and a nonempty group. Defaults to false. See Canceling jobs in progress. |
Set concurrency: null to disable concurrency for the step.
Compatibility with top-level attributes
The integer syntax and top-level concurrency_group and concurrency_method attributes remain supported. Both syntaxes use the same concurrency groups and scheduling behavior. cancel_in_progress has no top-level equivalent, so set it inside the concurrency map.
For example, this existing configuration is equivalent to the map above:
steps:
- command: "deploy.sh"
concurrency: 1
concurrency_group: "my-app/deploy"
concurrency_method: ordered
When you combine a map with top-level attributes, a nested group or method takes precedence before server validation. An omitted key inherits the corresponding top-level value. An explicit null clears that value instead of inheriting it. For example, method: null overrides concurrency_method: eager and selects ordered. Setting group: null with a positive limit is invalid, even if concurrency_group is set.
For concurrency group behavior and examples, see Controlling concurrency.
Example
steps:
- label: ":hammer: Tests"
commands:
- "npm install"
- "npm run tests"
branches: "main"
env:
NODE_ENV: "test"
agents:
npm: "true"
queue: "tests"
artifact_paths:
- "logs/**/*"
- "coverage/**/*"
parallelism: 5
timeout_in_minutes: 3
retry:
automatic:
- exit_status: -1
limit: 2
- exit_status: 143
limit: 2
- exit_status: 255
limit: 2
- label: "Visual diff"
commands:
- "npm install"
- "npm run visual-diff"
cancel_on_build_failing: true
retry:
automatic:
limit: 3
- label: "Skipped job"
command: "broken.sh"
cancel_on_build_failing: true
skip: "Currently broken and needs to be fixed"
- wait: ~
- label: ":shipit: Deploy"
command: "deploy.sh"
branches: "main"
concurrency:
limit: 1
group: "my-app/deploy"
method: eager
retry:
manual:
allowed: false
reason: "Sorry, you can't retry a deployment"
- wait: ~
- label: "Smoke test"
command: "smoke-test.sh"
soft_fail:
- exit_status: 1