Skip to main content
Version: 3.1.0

Introduction

Stroppy is a database stress testing CLI tool built as an extension to k6, Grafana's open-source load testing engine. You write test scripts in TypeScript, define data generators with precise distributions, and run benchmarks that produce detailed metrics and HTML reports.

Why k6?​

Database benchmarking tools tend to fall into two camps: simplistic single-threaded query runners, or sprawling frameworks that require their own infrastructure. Stroppy takes a different path by extending k6:

  • Virtual Users (VUs) — k6 manages concurrent goroutines that each execute your test script independently. You get real concurrency without thread management.
  • Scenarios — Define exactly how load ramps up, holds steady, or varies over time. Constant VUs, ramping VUs, shared iterations, per-VU iterations — all built in.
  • Thresholds — Set pass/fail criteria on any metric. If p95 latency exceeds 200ms, the test fails.
  • Real-time dashboard — Watch metrics live in the browser while the test runs.
  • HTML report export — Get a self-contained report at the end of every run.
  • Ecosystem — JSON output, InfluxDB, Prometheus, Datadog, and more output formats work out of the box.

Stroppy adds what k6 lacks for database testing: a driver abstraction, parameterized SQL execution, data generation with statistical distributions, and bulk insertion (including PostgreSQL COPY protocol).

Architecture​

┌──────────────────────────────────────────────────┐
│ Your Test Script (.ts) │
│ ┌─────────────┐ ┌────────────┐ ┌───────────┐ │
│ │ DriverX │ │ Generators │ │ k6 APIs │ │
│ │ .runQuery() │ │ R / S │ │ scenarios │ │
│ │ .insert() │ │ NewGen() │ │ thresholds│ │
│ └──────┬───────┘ └─────┬──────┘ └───────────┘ │
└─────────┼────────────────┼─────────────────────────┘
│ │
┌─────▼────────────────▼─────┐
│ k6/x/stroppy module │
│ (Go, compiled into k6) │
└─────┬────────────────┬─────┘
│ │
┌──────▼──────┐ ┌──────▼──────┐
│ Driver │ │ Generator │
│ Registry │ │ Engine │
│ (postgres) │ │ (uniform, │
│ │ │ normal, │
│ │ │ zipfian) │
└──────┬──────┘ └─────────────┘
│
┌──────▼──────┐
│ PostgreSQL │
│ (pgx) │
└─────────────┘

Installation​

Pre-built binaries​

Download from GitHub Releases.

Docker​

docker pull ghcr.io/stroppy-io/stroppy:latest

Build from source​

Requires Go 1.24.3+:

git clone https://github.com/stroppy-io/stroppy.git
cd stroppy
make build
# Binary at ./build/stroppy

Verify installation​

stroppy version
stroppy v3.1.0
k6 v1.6.0
pgx v5.8.0

This shows the versions of Stroppy itself and its key dependencies (k6 engine, PostgreSQL driver). For programmatic use, stroppy version --json outputs the same information as JSON.

Quick Start​

1. Generate a workspace​

stroppy gen --workdir mytest --preset=simple

This creates a directory with:

  • The stroppy binary (or symlink to it)
  • TypeScript test templates and type definitions
  • Helper framework files
  • package.json for npm dependencies

Available presets: simple, tpcb, tpcc, tpcds, execute_sql.

2. Install dependencies​

cd mytest
npm install

3. Run a test​

Stroppy resolves short preset names automatically — no need to type full paths:

# Against local PostgreSQL (default: postgres://postgres:postgres@localhost:5432)
stroppy run simple

# With a custom database URL
DRIVER_URL="postgres://user:pass@host:5432/mydb" stroppy run simple

4. Run with an SQL file​

Some workloads pair a TypeScript script with a SQL file. Stroppy auto-derives the SQL file from the preset name:

stroppy run tpcb # resolves tpcb.ts + tpcb.sql from built-in workloads
stroppy run tpcds tpcds-scale-100 # explicit SQL variant from the tpcds preset

5. Pass k6 arguments​

Everything after -- is forwarded to k6:

stroppy run simple -- --vus 10 --duration 30s

6. Select steps​

Use --steps or --no-steps to run only specific setup phases:

stroppy run tpcc --steps create_schema,load_data # only run these steps
stroppy run tpcc --no-steps load_data # skip data loading

A Minimal Test Script​

import { Options } from "k6/options";
import { Teardown } from "k6/x/stroppy";
import { DriverConfig_DriverType } from "./stroppy.pb.js";
import { DriverX, ENV } from "./helpers.ts";

export const options: Options = {};

const driver = DriverX.create().setup({
url: ENV("DRIVER_URL", "postgres://postgres:postgres@localhost:5432", "Database connection URL"),
driverType: DriverConfig_DriverType.DRIVER_TYPE_POSTGRES,
driverSpecific: {
oneofKind: "postgres",
postgres: {},
},
});

export default function () {
// Run a simple query
driver.exec("SELECT 1;");

// Run a parameterized query
driver.exec("SELECT :a + :b", { a: 10, b: 20 });
}

export function teardown() {
Teardown();
}

Docker Usage​

# Run built-in workloads directly
docker run --network host ghcr.io/stroppy-io/stroppy run simple

# TPC-B benchmark with custom DB
docker run --network host \
-e DRIVER_URL="postgres://user:pass@host:5432/db" \
ghcr.io/stroppy-io/stroppy run tpcb

# Generate a workspace to your host
docker run -v $(pwd):/workspace ghcr.io/stroppy-io/stroppy \
gen --workdir mytest --preset=simple

File Resolution​

When you run stroppy run tpcc, Stroppy resolves the script and SQL files through a search path:

  1. Current directory (./)
  2. ~/.stroppy/ (if it exists)
  3. Built-in workloads (embedded in the binary)

Script and SQL resolve independently — drop a custom tpcc.sql in your current directory to override the SQL while using the built-in tpcc.ts.

The extension determines the mode:

InputModeExample
No extensionPresetstroppy run tpcc
.tsScriptstroppy run bench.ts
.sqlSQL filestroppy run queries.sql
Quoted stringInline SQLstroppy run "SELECT 1"

Using the k6 Binary Directly​

Stroppy is a k6 extension. The build produces both stroppy and k6 binaries:

make build

# Use k6 directly with full k6 CLI
./build/k6 run --vus 10 --duration 30s test.ts

# JSON output
./build/k6 run --out json=results.json test.ts

# Stroppy commands via k6 extension
./build/k6 x stroppy run workloads/simple/simple.ts

Next Steps​