This guide shows how to manage LoadForge tests and run them automatically from GitHub using the CLI. It covers repo layout, required secrets, and sample workflows.

Repo layout

Tests live under tests/<slug>/:
tests/<slug>/
  locustfile.py
  config.json
config.json fields managed by the CLI:
{
  "users": 200,
  "rate": 1,
  "servers": 2,
  "host": "https://example.com:443",
  "apdex_target": 300,
  "p95_target": 600,
  "error_perc_target": 0,
  "region_servers": { "nyc3": 1, "sfo3": 1 }
}
Notes:
  • Slug is the unique test name.
  • host is protocol+hostname+port; the CLI resolves/creates the Host and sends host_id.
  • New tests require region present on create; for updates, region defaults to remote if omitted.
  • Only test_type = "load" is supported for pull/push currently.

Required secret

Add to your repo or org secrets:
  • API_KEY: your LoadForge API key (used as env var API_KEY).
References: Introduction, List Hosts, List Tests, Update Test, Start Run, Get Result

Install method in CI

Use npx (no install step needed; both aliases work):
npx loadforge-cli --help
# or
npx lf-cli --help
Or cache node_modules and install once:
npm ci
npx loadforge-cli --help

Workflow: sync configs on push to main

Sync local configs and locustfiles to LoadForge when PRs are merged. Creates new tests and updates existing ones by slug; optionally prunes remote tests not present locally.
name: Sync LoadForge tests

on:
  push:
    branches: [ main ]

jobs:
  sync:
    runs-on: ubuntu-latest
    permissions:
      contents: read
    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-node@v4
        with:
          node-version: 20

      - name: Push tests to LoadForge
        env:
          API_KEY: ${{ secrets.API_KEY }}
        run: |
          npx loadforge-cli push --dir tests --dry-run=false --allow-create --allow-delete
Behavior:
  • Intersection (same slug) → PATCH
  • Local-only → create (with --allow-create)
  • Remote-only → delete/prune (with --allow-delete)
  • Extended fields are attempted; if rejected, the CLI falls back to base fields.

Workflow: drift check (no changes)

Detect drift between main and LoadForge without making changes.
name: LoadForge drift check

on:
  pull_request:
    branches: [ main ]

jobs:
  check:
    runs-on: ubuntu-latest
    permissions:
      contents: read
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 20
      - name: Dry run push (no changes)
        env:
          API_KEY: ${{ secrets.API_KEY }}
        run: |
          npx loadforge-cli push --dir tests --dry-run

Workflow: run tests on demand (matrix by slug)

Start runs and wait for completion. The wait command exits with:
  • 0: run_status=3 and run_passed=true
  • 2: run_status=3 and run_passed=false (explanation printed)
  • 1: run_status>=4 (failure reason printed)
name: LoadForge run (matrix)

on:
  workflow_dispatch:
    inputs:
      duration:
        description: Minutes (>=2)
        required: true
        default: '5'

jobs:
  run:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        slug: [ lf-website ] # add more slugs here
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 20

      - name: Start run
        id: start
        env:
          API_KEY: ${{ secrets.API_KEY }}
        run: |
          RUN_ID=$(npx loadforge-cli start "${{ matrix.slug }}" -d "${{ github.event.inputs.duration }}")
          echo "RUN_ID=$RUN_ID" >> $GITHUB_OUTPUT

      - name: Wait for result
        env:
          API_KEY: ${{ secrets.API_KEY }}
        run: |
          npx loadforge-cli wait "${{ steps.start.outputs.RUN_ID }}"
Use the exit code to fail the job if the run failed to execute or if it completed but did not pass thresholds (apdex/error%/p95).

Workflow: nightly scheduled runs

name: Nightly LoadForge runs

on:
  schedule:
    - cron: '0 2 * * *' # 02:00 UTC daily

jobs:
  nightly:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        slug: [ lf-website ] # extend as needed
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 20

      - name: Start and wait
        env:
          API_KEY: ${{ secrets.API_KEY }}
        run: |
          RUN_ID=$(npx loadforge-cli start "${{ matrix.slug }}" -d 5)
          npx loadforge-cli wait "$RUN_ID"

Hosts management via config.host

  • Specify a host string in config.json, e.g., "host": "https://example.com:443".
  • On push, the CLI resolves to an existing Host (protocol/url/port match) or creates one if missing, and sends host_id automatically.
  • No need to store host IDs in git.

Pulling from LoadForge

To bootstrap or refresh local files:
npx loadforge-cli pull --out tests
This writes tests/<slug>/locustfile.py and tests/<slug>/config.json for all load tests. It writes host strings by resolving host_id via the Hosts API.

Creating new tests (local scaffold)

Create a new test folder (interactive or via flags). Then push with --allow-create to create it remotely.
# Interactive
npx loadforge-cli create

# Non-interactive
npx loadforge-cli create --name my-test --users 50 --host https://example.com:443
npx loadforge-cli push --allow-create

References

  • Intro/Auth: /api-reference/introduction
  • Hosts (list): /api-reference/endpoint/hosts-list
  • Tests (list): /api-reference/endpoint/tests-list
  • Tests (update): /api-reference/endpoint/tests-update
  • Run (start): /api-reference/endpoint/run-start
  • Result (get): /api-reference/endpoint/result-get