Skip to main content
Version: 4.0.0

Drivers & Configuration

Every Stroppy test needs a database driver. This page covers how to configure one — from a single flag on the command line to fine-grained pool tuning and multi-driver setups.

Quick Start

The fastest way to get a driver running is two lines of TypeScript:

import { DriverX, declareDriverSetup } from "./helpers.ts";

const config = declareDriverSetup(0, {
url: "postgres://postgres:postgres@localhost:5432",
driverType: "postgres",
});

const driver = DriverX.create().setup(config);

declareDriverSetup(0, {...}) declares driver slot 0 with defaults that the CLI can override. DriverX.create().setup(config) creates the driver and configures it. After this, driver.exec(...), driver.insert(...), and driver.begin(...) are all available.

Or skip TypeScript entirely — use a built-in preset from the command line:

stroppy run simple -d pg

CLI Flags

Three flag families control drivers from the command line.

-d / --driver — Driver Presets

Select a pre-configured driver by short name:

stroppy run tpcc -d pg
stroppy run tpcc -d mysql
stroppy run tpcc -d pico

The flag supports several syntax forms:

FormExampleMeaning
Space-d pgDriver 0, preset pg
Equals--driver=pgDriver 0, preset pg
Indexed (short)-d1 mysqlDriver 1, preset mysql
Indexed (long)--driver1=mysqlDriver 1, preset mysql
Raw JSON-d '{"driverType":"postgres","url":"..."}'Driver 0, inline config

Without a number suffix, the index defaults to 0.

-D / --driver-opt — Field Overrides

Override individual fields of a driver configuration:

stroppy run tpcc -d pg -D url=postgres://prod:5432/mydb
stroppy run tpcc -d mysql -D url=root:secret@tcp(db.local:3306)/bench

Like -d, this flag supports indexed and equals forms:

FormExample
Space-D url=postgres://...
Equals-D=url=postgres://...
Indexed-D1 url=...
Long form--driver-opt url=...
Long indexed--driver1-opt url=...
Long indexed equals--driver1-opt=url=...

Known override keys are url, driverType, and defaultInsertMethod. Any other key is passed through as-is to the TypeScript layer.

-e / --env — Environment Overrides

Set environment variables for the test script:

stroppy run tpcc -e pool_size=200 -e scale_factor=10

Keys are auto-uppercasedpool_size becomes POOL_SIZE in the script. The flag accepts both space and equals forms:

-e SCALE_FACTOR=10
-e=SCALE_FACTOR=10
--env SCALE_FACTOR=10
--env=SCALE_FACTOR=10

See the Environment Overrides section below for precedence rules.

Driver Presets

Three presets are built in:

PresetdriverTypeDefault URLDefault Insert Method
pgpostgrespostgres://postgres:postgres@localhost:5432copy_from
mysqlmysqlmyuser:mypassword@tcp(localhost:3306)/mydb?charset=utf8mb4&parseTime=True&loc=Localplain_bulk
picopicodatapostgres://admin:T0psecret@localhost:1331plain_bulk

Presets are case-insensitive. A preset sets defaults; you can override any field with -D:

# Use pg preset but connect to a different host
stroppy run tpcc -d pg -D url=postgres://user:pass@db.prod:5432/bench

# Use mysql preset but switch insert method
stroppy run tpcc -d mysql -D defaultInsertMethod=plain_query

declareDriverSetup in Detail

function declareDriverSetup(index: number, defaults: DriverSetup): DriverSetup;

This is the bridge between your TypeScript defaults and CLI overrides. It reads the STROPPY_DRIVER_<index> env var (set by -d/-D flags), parses it as JSON, and merges CLI values over your defaults. Fields not set by the CLI keep their script-defined values.

DriverSetup fields

FieldTypeDefaultDescription
urlstringDatabase connection URL
driverType"postgres" | "mysql" | "picodata"Which driver to use
errorMode"silent" | "log" | "throw" | "fail" | "abort""log"How query errors are handled
defaultInsertMethod"plain_query" | "plain_bulk" | "copy_from""plain_bulk"Insert strategy for driver.insert()
defaultTxIsolation"db_default" | "read_uncommitted" | "read_committed" | "repeatable_read" | "serializable" | "conn" | "none""db_default"Transaction isolation level for driver.begin()
bulkSizenumber500Rows per bulk INSERT statement
poolPoolConfigUnified pool configuration sugar (see below)
postgresPostgresConfigPostgreSQL-specific pool settings
sqlSqlConfigGeneric SQL pool settings (MySQL)

Error modes

  • silent — Record error metric only, no console output.
  • log — Record metric + print to console. This is the default.
  • throw — Rethrow the error. Your script must catch it.
  • fail — Mark the k6 test as failed, continue execution (exit code 110).
  • abort — Immediately stop the test via test.abort() (exit code 108).

Error mode precedence: STROPPY_ERROR_MODE env var > config.errorMode > default ("log").

Merge behavior

CLI fields override TypeScript defaults field-by-field. Only fields explicitly set in the CLI JSON are merged — everything else keeps the script's default value:

// Script declares:
const config = declareDriverSetup(0, {
url: "postgres://localhost:5432",
driverType: "postgres",
pool: { maxConns: 10, minConns: 2 },
});

// CLI: stroppy run test.ts -d pg -D url=postgres://prod:5432
// Result: url is overridden, driverType stays "postgres", pool stays {maxConns: 10, minConns: 2}

Pool Configuration

The pool field provides a unified interface that maps to the correct driver-specific pool config based on driverType.

const config = declareDriverSetup(0, {
url: "postgres://localhost:5432",
driverType: "postgres",
pool: {
maxConns: 20,
minConns: 5,
maxConnLifetime: "1h",
maxConnIdleTime: "10m",
},
});

How pool maps to driver-specific config

For postgres and picodata (driverType: "postgres" or "picodata"), pool maps to PostgresConfig:

pool fieldPostgresConfig field
maxConnsmaxConns
minConnsminConns
maxConnLifetimemaxConnLifetime
maxConnIdleTimemaxConnIdleTime

For mysql (driverType: "mysql"), pool maps to SqlConfig:

pool fieldSqlConfig field
maxConnsmaxOpenConns
minConnsmaxIdleConns
maxConnLifetimeconnMaxLifetime
maxConnIdleTimeconnMaxIdleTime

Explicit vs. sugar

If you set postgres or sql directly, they take priority over pool:

// pool is ignored here — postgres takes priority
const config = declareDriverSetup(0, {
url: "postgres://localhost:5432",
driverType: "postgres",
pool: { maxConns: 10 }, // ignored
postgres: { maxConns: 20 }, // this wins
});

Full PostgresConfig fields

When you need PostgreSQL-specific settings beyond what pool offers:

const config = declareDriverSetup(0, {
url: "postgres://localhost:5432",
driverType: "postgres",
postgres: {
maxConns: 20,
minConns: 5,
minIdleConns: 3,
maxConnLifetime: "1h",
maxConnIdleTime: "10m",
traceLogLevel: "warn",
defaultQueryExecMode: "cache_statement",
statementCacheCapacity: 512,
descriptionCacheCapacity: 256,
},
});

Multi-Driver Setup

Stroppy supports multiple simultaneous database connections. This is useful for cross-database tests, migration validation, or comparing query plans across engines.

From the CLI

Use indexed flags to configure multiple drivers:

stroppy run bench.ts -d0 pg -d1 mysql
stroppy run bench.ts -d pg -d1 pico -D1 url=postgres://admin:T0psecret@remote:1331

In TypeScript

Each driver gets its own slot index:

const pgConfig = declareDriverSetup(0, {
url: "postgres://postgres:postgres@localhost:5432",
driverType: "postgres",
pool: { maxConns: 2, minConns: 2 },
});
const pgDriver = DriverX.create().setup(pgConfig);

const mysqlConfig = declareDriverSetup(1, {
url: "root:pass@tcp(localhost:3306)/mydb",
driverType: "mysql",
});
const mysqlDriver = DriverX.create().setup(mysqlConfig);

Shared vs. per-VU drivers

Where you call .setup() determines sharing semantics:

  • Init phase (top-level module scope) — The driver's connection pool is shared across all VUs. This is the common case.
  • Iteration phase (inside default() or setup()) — Each VU gets its own driver instance and pool.
// Shared: created at init, one pool for all VUs
const sharedDriver = DriverX.create().setup(sharedConfig);

// Per-VU: created at init, configured per iteration
const vuDriver = DriverX.create();

export default function () {
vuDriver.setup({
url: "postgres://localhost:5432?application_name=vu_" + exec.vu.idInTest,
driverType: "postgres",
pool: { maxConns: 1, minConns: 1 },
});

// Both drivers are usable here
sharedDriver.exec("SELECT 1");
vuDriver.exec("SELECT 1");
}

The .setup() call is safe to invoke on every iteration — it only configures the driver once.

-e Environment Overrides

The -e flag sets environment variables that your test script can read via the ENV() helper or k6's __ENV object.

Precedence

From highest to lowest priority:

  1. Real environment — Variables already set in the shell (export SCALE_FACTOR=100). These always win. If a real env var exists, the -e value is silently ignored with a warning.
  2. -e overrides — Values from the command line (-e scale_factor=50).
  3. Driver config — Values from -d/-D flags (passed as STROPPY_DRIVER_N env vars).
  4. TypeScript defaults — The fallback values in declareDriverSetup() and ENV().

Auto-uppercasing

All -e keys are uppercased before being set. This means these are equivalent:

stroppy run tpcc -e scale_factor=10
stroppy run tpcc -e SCALE_FACTOR=10
stroppy run tpcc -e Scale_Factor=10

All three set SCALE_FACTOR=10 in the script environment.

Multiple overrides

stroppy run tpcc -e scale_factor=10 -e pool_size=200 -e custom_flag=true

When the same key appears multiple times, the last value wins.

Driver Types

Stroppy supports three database drivers. Each has different capabilities:

"postgres"

Full-featured PostgreSQL driver built on pgx.

  • Queries: Full SQL support with :param syntax
  • Transactions: All isolation levels
  • Insert methods: plain_query, plain_bulk, copy_from
  • Pool config: PostgresConfig (pgx pool)
  • COPY protocol: Yes — use copy_from for bulk loads (5-10x faster than individual inserts)

"mysql"

MySQL driver using Go's database/sql interface.

  • Queries: Full SQL support with :param syntax
  • Transactions: All isolation levels
  • Insert methods: plain_query, plain_bulk (copy_from is not supported)
  • Pool config: SqlConfig (database/sql pool)

"picodata"

Picodata driver using the PostgreSQL wire protocol.

  • Queries: SQL support with :param syntax
  • Transactions: Not supported (returns error)
  • Insert methods: plain_query, plain_bulk (copy_from is not supported)
  • Pool config: PostgresConfig (pgx pool, same as PostgreSQL)

Capability matrix

Capabilitypostgresmysqlpicodata
plain_query insertYesYesYes
plain_bulk insertYesYesYes
copy_from insertYesNoNo
TransactionsYesYesNo
:param syntaxYesYesYes
Pool typepgxdatabase/sqlpgx

How It Works Under the Hood

Understanding the plumbing helps when debugging configuration issues.

The STROPPY_DRIVER_N mechanism

When you use -d and -D flags, the Go CLI:

  1. Looks up the preset (if -d was used) to get base values (driverType, url, defaultInsertMethod).
  2. Applies -D overrides field by field on top of the preset.
  3. Serializes the result to JSON.
  4. Sets it as the STROPPY_DRIVER_0 environment variable (or STROPPY_DRIVER_1, etc.).

On the TypeScript side, declareDriverSetup(0, defaults) reads STROPPY_DRIVER_0, parses the JSON, and merges CLI values over script defaults. The merged config is then passed to DriverX.create().setup(config), which converts it to the protobuf DriverConfig message and sends it to the Go driver layer.

CLI flags                    Environment              TypeScript
───────── ─────────── ──────────
-d pg → STROPPY_DRIVER_0= → declareDriverSetup(0, defaults)
-D url=postgres://... {"driverType":"postgres", merges CLI JSON over defaults
"url":"postgres://...", → DriverX.create().setup(merged)
"defaultInsertMethod": converts to protobuf
"copy_from"} → Go driver.Setup(proto)

Why declareDriverSetup exists

It serves a dual purpose. At runtime, it merges CLI config over script defaults. During the probe phase (when Stroppy inspects a script without executing it), the DeclareDriverSetup spy function captures the declared defaults so the CLI can report what a script expects. This is how stroppy probe can show a script's driver requirements without running it.

Pass-through fields

The -D flag accepts any key=value pair. Known fields (url, driverType, defaultInsertMethod) are set on the Go struct; everything else goes into an Extra map that is serialized into the JSON and passed through to TypeScript. This lets you define custom fields in your script and override them from the CLI:

const config = declareDriverSetup(0, {
url: "postgres://localhost:5432",
driverType: "postgres",
});

// Access a custom CLI-provided field
const customTimeout = (config as any).queryTimeout ?? "30s";
stroppy run bench.ts -d pg -D queryTimeout=60s