The Independent Blueprint for Modern Load Testing & Grafana k6 Performance Engineering

k6 in CI/CD: Automated Pipeline Orchestration in Azure DevOps and GitHub Actions

Posted on May 24, 2026 in Observability

Load testing is not a one-off task. If you only run performance validations before major releases, you will inevitably catch regressions too late. A single bad database query commit or an unoptimized middleware function can silently double your API response times. To catch these regressions early, you must automate your load tests inside your continuous integration (CI) and continuous delivery (CD) pipelines.

Let us look at how to structure automated pipelines in Azure DevOps and GitHub Actions, orchestrating compile caching and automated HTML report archiving.

1. Azure DevOps Pipeline Orchestration

This Azure DevOps pipeline runs on a standard Linux build agent. To optimize speed, it caches Go module dependencies persistently across runs. It installs the Go compiler toolchain, installs the xk6 package manager globally, builds a customized k6 binary with tracing and database support, runs the test headless, and archives the interactive HTML report:

trigger:
  branches:
    include:
      - main
      - develop

pool:
  vmImage: 'ubuntu-latest'

variables:
  - name: GO_VERSION
    value: '1.25.5'
  - name: K6_VERSION
    value: 'v0.51.0'

stages:
- stage: PerformanceTest
  displayName: 'Execute Custom Load Test Suite'
  jobs:
  - job: RunK6
    displayName: 'Compile and Execute k6'
    steps:
    - task: UseGo@2
      displayName: 'Install Go Toolchain'
      inputs:
        version: '$(GO_VERSION)'

    # Cache Go modules to optimize compilation speed
    - task: Cache@2
      displayName: 'Cache Go Modules'
      inputs:
        key: 'go | "$(Agent.OS)" | go.mod'
        restoreKeys: |
          go | "$(Agent.OS)"
        path: '$(GOPATH)/pkg/mod'

    - script: |
        echo "Installing xk6..."
        go install go.k6.io/xk6/cmd/xk6@latest
        echo "Compiling custom k6 binary with extensions..."
        $(go env GOPATH)/bin/xk6 build $(K6_VERSION) \
          --with github.com/grafana/xk6-distributed-tracing@latest \
          --with github.com/grafana/xk6-sql@latest
      displayName: 'Compile Custom xk6 Binary'

    # Execute the load test
    - script: |
        mkdir -p $(System.DefaultWorkingDirectory)/outputs
        export K6_WEB_DASHBOARD=true
        export K6_WEB_DASHBOARD_PORT=-1 # Headless, export-only mode
        export K6_WEB_DASHBOARD_EXPORT=$(System.DefaultWorkingDirectory)/outputs/test_report.html
        
        ./k6 run \
          --out json=$(System.DefaultWorkingDirectory)/outputs/metrics_raw.json \
          --summary-export=$(System.DefaultWorkingDirectory)/outputs/metrics_summary.json \
          $(System.DefaultWorkingDirectory)/load_script.js
      displayName: 'Execute Load Test Scenario'
      env:
        DB_CONNECTION_STRING: $(PROD_DB_SECRET)
        BASE_URL: 'https://quickpizza.grafana.com'
      continueOnError: false # Fail-fast evaluation based on k6 thresholds

    # Publish the interactive HTML report
    - task: PublishHtmlReport@1
      displayName: 'Publish HTML Performance Dashboard'
      condition: always()
      inputs:
        reportDir: '$(System.DefaultWorkingDirectory)/outputs'
        tabName: 'Load Test Report'

    # Publish the raw JSON metrics artifact
    - task: PublishPipelineArtifact@1
      displayName: 'Publish Raw Execution Artifacts'
      condition: always()
      inputs:
        targetPath: '$(System.DefaultWorkingDirectory)/outputs'
        artifact: 'PerformanceMetrics'
        publishLocation: 'pipeline'

2. GitHub Actions Workflow Orchestration

If your team uses GitHub, you can achieve the same pipeline automation using GitHub Actions. This workflow handles Go environment provisioning, registers compile caching, compiles a customized xk6 executable, runs the load script, and uploads the interactive HTML report as an artifact archive:

name: "Continuous Enterprise Load Testing Pipeline"

on:
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]
  workflow_dispatch:

jobs:
  performance-validation:
    name: "Build xk6 & Run Validation"
    runs-on: ubuntu-latest
    
    steps:
      - name: "Checkout Code"
        uses: actions/checkout@v4

      - name: "Set up Go Environment"
        uses: actions/setup-go@v5
        with:
          go-version: '1.25.5'
          cache: true

      - name: "Restore Go Build Cache"
        uses: actions/cache@v4
        with:
          path: |
            ~/.cache/go-build
            ~/go/pkg/mod
          key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
          restore-keys: |
            ${{ runner.os }}-go-

      - name: "Build Enterprise xk6 Executable"
        run: |
          go install go.k6.io/xk6/cmd/xk6@latest
          ~/go/bin/xk6 build v0.51.0 \
            --with github.com/grafana/xk6-disruptor@latest \
            --with github.com/grafana/xk6-distributed-tracing@latest

      - name: "Run Load Test Suite"
        run: |
          mkdir -p reports
          export K6_WEB_DASHBOARD=true
          export K6_WEB_DASHBOARD_PORT=-1 # Run headless, export-only
          export K6_WEB_DASHBOARD_EXPORT=reports/interactive_report.html
          
          ./k6 run \
            --out json=reports/raw_telemetry.json \
            load_script.js
        env:
          K6_CLOUD_TOKEN: ${{ secrets.K6_CLOUD_API_TOKEN }}
          API_TARGET_URL: 'https://quickpizza.grafana.com'

      - name: "Publish Interactive Report"
        uses: actions/upload-artifact@v4
        if: always()
        with:
          name: performance-report
          path: reports/
          retention-days: 14

By automating your load scripts within these pipeline wrappers, you establish a solid performance gate that prevents unoptimized code from ever reaching your production environments.

To learn how to configure the real-time reporting formats that these pipelines export, read k6 Reporting: Real-time Web Dashboards and Headless NDJSON Streaming. If you want to understand how the xk6 bridge maps your Go structures to JavaScript, check out xk6 Architecture: Extending the k6 Runtime with Custom Go Bindings. If you are executing these load testing pipelines on Windows, see our framework guide on k6 Workload Execution and static Gzip HTML Report Generation on Windows.