buildkite

robBowes's avatarfrom robBowes

Buildkite CI/CD pipeline configuration, API integration, and workflow automation. Use when creating or modifying Buildkite pipelines (pipeline.yml), interacting with Buildkite REST/GraphQL APIs, configuring agents, managing artifacts, implementing caching strategies, or automating CI/CD workflows. Covers step types, conditional execution, parallelism, plugins, and monorepo patterns.

⭐0stars🔀0forks📁View on GitHub🕐Updated Jan 6, 2026⬇️1downloads

When & Why to Use This Skill

This Claude skill provides comprehensive expertise in Buildkite CI/CD pipeline configuration, API integration, and workflow automation. It enables developers to design robust 'pipeline.yml' structures, manage complex step types, and implement advanced delivery patterns such as matrix builds, parallelism, and dynamic pipeline generation. By leveraging this skill, teams can optimize their software delivery lifecycle with efficient caching strategies, artifact management, and seamless plugin integrations for Docker, AWS, and more.

Use Cases

  • Designing complex CI/CD workflows: Create multi-stage pipelines featuring conditional execution, manual approval gates (block steps), and inter-pipeline triggers.
  • Optimizing build performance: Implement parallelism, sharding, and S3-backed caching plugins to drastically reduce build times and resource overhead.
  • Managing Monorepo environments: Configure dynamic pipeline uploads and file-change detection (if_changed) to trigger targeted testing and deployment for specific packages.
  • Cloud and Container Integration: Automate containerized workflows using Docker and Docker Compose plugins, and manage secure image deployments to AWS ECR.
  • Advanced Agent Orchestration: Customize build environments using agent hooks, metadata tracking, and specific agent targeting for specialized hardware or OS requirements.
namebuildkite
descriptionBuildkite CI/CD pipeline configuration, API integration, and workflow automation. Use when creating or modifying Buildkite pipelines (pipeline.yml), interacting with Buildkite REST/GraphQL APIs, configuring agents, managing artifacts, implementing caching strategies, or automating CI/CD workflows. Covers step types, conditional execution, parallelism, plugins, and monorepo patterns.

Buildkite CI/CD

Pipeline Configuration (pipeline.yml)

Step Types

env:
  CI: "true"

agents:
  queue: "default"

steps:
  # Command step
  - label: ":hammer: Build"
    key: "build"
    commands:
      - "npm install"
      - "npm run build"
    artifact_paths: "dist/**/*"
    timeout_in_minutes: 30

  # Wait step - sync point
  - wait: ~

  # Block step - manual gate
  - block: ":rocket: Deploy?"
    if: build.branch == "main"
    fields:
      - select: "Environment"
        key: "env"
        options:
          - { label: "Staging", value: "staging" }
          - { label: "Production", value: "prod" }

  # Input step - collect data without blocking
  - input: "Version"
    key: "version-input"
    fields:
      - text: "Version"
        key: "version"
        required: true

  # Trigger step - trigger another pipeline
  - trigger: "deploy-pipeline"
    build:
      branch: "${BUILDKITE_BRANCH}"
      env:
        VERSION: "${VERSION}"

  # Group step - organize steps
  - group: ":test_tube: Tests"
    steps:
      - label: "Unit"
        command: "npm test"
      - label: "Integration"
        command: "npm run test:integration"

Conditional Execution

steps:
  # Branch conditions
  - label: "Deploy"
    command: "deploy.sh"
    if: build.branch == "main"

  # Message patterns
  - label: "Skip Deploy"
    command: "echo skipped"
    if: build.message !~ /\[skip-deploy\]/

  # Multiple conditions
  - label: "Release"
    command: "release.sh"
    if: build.branch == "main" && build.tag != null

  # File change conditions (agent-evaluated)
  - label: "API Tests"
    command: "npm run test:api"
    if_changed:
      include: ["packages/api/**"]
      exclude: ["**/*.md"]

Dependencies

steps:
  - label: "Build"
    key: "build"
    command: "npm run build"

  - label: "Test"
    depends_on: "build"
    command: "npm test"

  - label: "Deploy"
    depends_on:
      - "build"
      - "test"
    allow_dependency_failure: false
    command: "deploy.sh"

Parallelism and Concurrency

steps:
  # Parallel jobs (sharding)
  - label: "Test %n"
    command: |
      SHARD=$((BUILDKITE_PARALLEL_JOB + 1))
      npm test -- --shard=${SHARD}/${BUILDKITE_PARALLEL_JOB_COUNT}
    parallelism: 4

  # Concurrency control (limit simultaneous runs)
  - label: "Deploy"
    command: "deploy.sh"
    concurrency: 1
    concurrency_group: "prod-deploy"
    concurrency_method: "eager"  # or "ordered"

Matrix Builds

steps:
  - label: "Node {{matrix.node}} / {{matrix.os}}"
    command: "npm test"
    matrix:
      setup:
        node: ["18", "20", "22"]
        os: ["linux", "darwin"]
      adjustments:
        - with: { node: "18", os: "darwin" }
          soft_fail: true
        - with: { node: "22", os: "darwin" }
          skip: true

Retry Strategies

steps:
  - label: "Flaky Test"
    command: "npm test"
    retry:
      automatic:
        - exit_status: -1     # Agent lost
          limit: 2
        - exit_status: 255    # Timeout
          limit: 1
        - exit_status: "*"    # Any failure
          limit: 2
      manual:
        allowed: true
        permit_on_passed: false

  # Soft fail - don't block pipeline
  - label: "Optional Check"
    command: "lint.sh"
    soft_fail:
      - exit_status: 1

Dynamic Pipelines

Upload pipeline steps dynamically:

steps:
  - label: ":pipeline: Generate"
    command: |
      cat <<EOF | buildkite-agent pipeline upload
      steps:
        - label: "Dynamic Step"
          command: "echo generated"
      EOF

Or from a script:

#!/bin/bash
# generate-pipeline.sh
PACKAGES=$(find packages -name package.json -exec dirname {} \;)

echo "steps:"
for pkg in $PACKAGES; do
  name=$(basename $pkg)
  echo "  - label: ':package: Test $name'"
  echo "    command: 'cd $pkg && npm test'"
done
steps:
  - label: ":pipeline: Upload"
    command: "./generate-pipeline.sh | buildkite-agent pipeline upload"

Artifacts

steps:
  - label: "Build"
    command: "npm run build"
    artifact_paths:
      - "dist/**/*"
      - "coverage/**/*"
      - "!dist/**/*.map"  # Exclude source maps

  - wait: ~

  - label: "Deploy"
    command: |
      buildkite-agent artifact download "dist/**/*" .
      deploy.sh

CLI commands:

# Upload
buildkite-agent artifact upload "dist/**/*"
buildkite-agent artifact upload "report.html" --job $BUILDKITE_JOB_ID

# Download
buildkite-agent artifact download "dist/**/*" ./output
buildkite-agent artifact download "*" . --step "build"

# Search
buildkite-agent artifact search "*.tar.gz"

Caching

Cache Plugin (S3 backend)

env:
  BUILDKITE_PLUGIN_S3_CACHE_BUCKET: "my-cache-bucket"

steps:
  - label: "Build"
    command: "npm ci && npm run build"
    plugins:
      - cache#v1.8.0:
          manifest: package-lock.json
          path: node_modules
          backend: s3
          compression: zstd

      # Multiple caches
      - cache#v1.8.0:
          key: "turbo-{{ checksum 'turbo.json' }}-{{ .Branch }}"
          restore-keys:
            - "turbo-{{ checksum 'turbo.json' }}-"
            - "turbo-"
          path: .turbo/cache
          backend: s3

Cache Key Interpolation

Template Description
{{ checksum 'file' }} SHA256 of file
{{ .Branch }} Branch name
{{ .Commit }} Full commit SHA
{{ .BuildNumber }} Build number
{{ arch }} CPU architecture

Plugins

Docker Plugin

steps:
  - command: "npm test"
    plugins:
      - docker#v5.13.0:
          image: "node:20"
          workdir: /app
          environment:
            - NODE_ENV=test
            - CI
          volumes:
            - "./:/app"
          mount-checkout: true
          propagate-uid-gid: true
          propagate-aws-auth-tokens: true

Docker Compose Plugin

steps:
  - command: "npm test"
    plugins:
      - docker-compose#v5.8.0:
          run: app
          config: docker-compose.ci.yml
          env:
            - CI=true

ECR Plugin

steps:
  - command: "./build.sh"
    plugins:
      - ecr#v2.10.0:
          credential-helper: true
          account-ids: ["123456789012"]
          region: "us-east-1"

Artifacts Plugin

steps:
  - label: "Download and Run"
    plugins:
      - artifacts#v1.9.4:
          download:
            - from: "dist.tar.gz"
              to: "/tmp/dist.tar.gz"
              step: "build"
          upload:
            - from: "results/**/*"

Annotations

# Add annotation
buildkite-agent annotate "Build complete!" --style success --context deploy

# Styles: success, info, warning, error
buildkite-agent annotate "<details><summary>Logs</summary>...</details>" --style info

# Append to existing
buildkite-agent annotate "More info" --context deploy --append

# Markdown supported
buildkite-agent annotate "## Results\n| Test | Status |\n|------|--------|\n| Unit | ✅ |" --style info

Metadata

# Set metadata
buildkite-agent meta-data set "version" "1.2.3"
buildkite-agent meta-data set "deploy-url" "https://app.example.com"

# Get metadata
VERSION=$(buildkite-agent meta-data get "version")
buildkite-agent meta-data get "version" --default "0.0.0"

# Check existence
buildkite-agent meta-data exists "version" && echo "exists"

# List keys
buildkite-agent meta-data keys

Environment Variables

Built-in Variables

Variable Description
BUILDKITE_BUILD_ID UUID of build
BUILDKITE_BUILD_NUMBER Sequential build number
BUILDKITE_BRANCH Branch name
BUILDKITE_COMMIT Commit SHA
BUILDKITE_TAG Git tag (if tagged)
BUILDKITE_MESSAGE Commit message
BUILDKITE_PIPELINE_SLUG Pipeline slug
BUILDKITE_STEP_KEY Step key
BUILDKITE_JOB_ID Current job ID
BUILDKITE_PARALLEL_JOB Parallel job index (0-based)
BUILDKITE_PARALLEL_JOB_COUNT Total parallel jobs
BUILDKITE_ARTIFACT_PATHS Artifact upload paths

Pipeline-level Env

env:
  NODE_ENV: "test"
  DOCKER_BUILDKIT: "1"

steps:
  - label: "Build"
    env:
      DEBUG: "true"  # Step-level override
    command: "npm run build"

Agent Configuration

Agent Targeting

steps:
  - label: "Build"
    agents:
      queue: "default"

  - label: "GPU Test"
    agents:
      queue: "gpu"
      gpu: "true"

  - label: "macOS Build"
    agents:
      os: "darwin"
      xcode: "15"

Agent Hooks

Located in /etc/buildkite-agent/hooks/:

# hooks/environment - set env vars
#!/bin/bash
export NPM_TOKEN=$(aws secretsmanager get-secret-value --secret-id npm-token --query SecretString --output text)

# hooks/pre-command - before each command
#!/bin/bash
echo "--- Setting up environment"

# hooks/post-command - after each command
#!/bin/bash
echo "--- Cleanup"

# hooks/pre-checkout - before git checkout
# hooks/post-checkout - after git checkout
# hooks/pre-exit - before job exits

API Reference

For REST API endpoints, GraphQL queries, authentication, and rate limits, see API.md.

Complete Example

# .buildkite/pipeline.yml
env:
  CI: "true"
  DOCKER_BUILDKIT: "1"

agents:
  queue: "default"

steps:
  - label: ":npm: Install"
    key: "install"
    command: "npm ci"
    plugins:
      - cache#v1.8.0:
          manifest: package-lock.json
          path: node_modules
          backend: s3

  - wait: ~

  - group: ":white_check_mark: Checks"
    steps:
      - label: ":eslint: Lint"
        command: "npm run lint"
        depends_on: "install"

      - label: ":typescript: Types"
        command: "npm run typecheck"
        depends_on: "install"

  - label: ":hammer: Build"
    key: "build"
    command: "npm run build"
    depends_on: "install"
    artifact_paths: "dist/**/*"

  - wait: ~

  - label: ":test_tube: Test %n"
    key: "test"
    parallelism: 4
    command: |
      SHARD=$((BUILDKITE_PARALLEL_JOB + 1))
      npm test -- --shard=${SHARD}/${BUILDKITE_PARALLEL_JOB_COUNT}
    depends_on: "build"
    artifact_paths: "test-results/**/*"
    retry:
      automatic:
        - exit_status: -1
          limit: 2

  - wait: ~
    continue_on_failure: true

  - label: ":junit: Annotate"
    plugins:
      - junit-annotate#v2.7.0:
          artifacts: "test-results/**/*.xml"

  - block: ":rocket: Deploy?"
    if: build.branch == "main"

  - label: ":shipit: Deploy"
    command: "./deploy.sh"
    if: build.branch == "main"
    concurrency: 1
    concurrency_group: "production"