A production-grade, TypeScript-first load testing framework built on Grafana k6 — with a two-layer architecture, reusable helpers and patterns, first-class observability, and strict multi-client isolation.
Writing one-off k6 scripts is easy. Running repeatable, reviewable, observable load tests across many services and teams is not. This framework solves the second problem:
- Two-layer architecture — a reusable generic core (
src/) shared by every workload, and isolated per-client layers (clients/) that never leak into each other. - Batteries included — HTTP/WS/GraphQL helpers, auth/retry/pagination/correlation/chaos patterns, a metrics engine, SLO evaluation, RBAC, secrets management, and self-contained HTML reporting.
- Observability native — overhead detection, generator health, distributed tracing (W3C / B3 / Jaeger), and Pyroscope profiling.
- One runner, strong guardrails — a single CLI enforces a canonical scenario taxonomy and safety gates so tests stay consistent and CI-friendly.
| Tool | Version | Notes |
|---|---|---|
| k6 | v1.6.1 | Test execution engine (goja runtime, not Node.js) |
| Node.js | >= 18 | CLI tooling, report generation, docs |
| pnpm | 11 | The only supported package manager |
| Docker + Compose | optional | Local observability stack (infrastructure/) |
| Go | 1.25+ | Only for building a custom k6 binary (bin/build-binary.sh) |
# 1. Install dependencies (pnpm only)
pnpm install
# 2. Run the reference smoke test
# RBAC fails closed; _reference ships config/rbac.json with one
# developer-role identity for the quick start (see clients/_reference/README.md#rbac)
K6_USER=reference-dev ./bin/run-test.sh --client=_reference --scenario=api/smoke-users --profile=smoke
# 3. Open the self-contained HTML report
open reports/_reference/api_smoke-users/html-report-*.htmlEvery run goes through ./bin/run-test.sh, which requires both a client and a scenario:
./bin/run-test.sh --client=<name> --scenario=<bucket>/<path> --profile=<name>--client=<name>— selects theclients/<name>/directory.--scenario=<bucket>/<path>— the path must start with one of the 5 canonical buckets below.--profile=<name>— named load intensity (e.g.smoke,load,stress,soak).
| Bucket | Purpose | Reference example |
|---|---|---|
api/ |
Single-endpoint smoke probes | clients/_reference/scenarios/api/smoke-users.ts |
flow/ |
Multi-step integration flows | clients/_reference/scenarios/flow/auth-flow.ts |
domain/ |
Service-level scenarios (domain/<service>/<action>.ts) |
clients/_reference/scenarios/domain/orders-lifecycle.ts |
chaos/ |
Fault-injection / resilience scenarios | clients/_reference/scenarios/chaos/fci-spike.ts |
perf/ |
Capacity, breakpoint, stress, soak | clients/_reference/scenarios/perf/breakpoint-tier.ts |
Scenarios can opt into a gate so the runner refuses to run them without an explicit flag:
export const gate = "experimental"; // also: "quarantined" | "unsafe"Pass the matching flag (--experimental, --quarantined, --unsafe) to unlock. Gated scenarios exit with code 108 otherwise.
k6-enterprise-framework/
├── src/ # Generic layer — shared across all clients
│ ├── core/ # Config, CLI, validation, RBAC, SLO, secrets
│ ├── helpers/ # HTTP, data, Redis, WS, GraphQL, upload, browser, crypto
│ ├── patterns/ # Auth, retry, pagination, correlation, chaos, funnel
│ ├── metrics/ # Metrics engine + specialized calculators
│ ├── observability/ # Overhead detection, health, tracing, Pyroscope
│ ├── reporting/ # HTML/JSON reports, capacity & trend analysis
│ ├── integrations/ # Notifications, Slack bot
│ ├── node/ # Node-only modules (never imported from k6 scenarios)
│ └── types/ # Shared TypeScript type definitions
├── clients/
│ ├── _reference/ # Canonical example scenarios — start here
│ ├── _benchmark/ # Framework overhead benchmarks
│ └── examples/ # Cookbook-style examples
├── shared/ # JSON schemas, profiles, templates
├── bin/ # CLI tooling (run-test, generate-report, validate-config…)
├── test/ # Vitest unit tests
├── docs-site/ # Docusaurus documentation (EN + ES)
├── mcp-server/ # MCP server for AI-assisted test creation
├── infrastructure/ # Docker Compose, Grafana dashboards, K8s
└── cmd/ # Custom k6 binary embedding (Go / xk6)
| Alias | Path |
|---|---|
@core/* |
src/core/* |
@helpers/* |
src/helpers/* |
@patterns/* |
src/patterns/* |
@observability/* |
src/observability/* |
@types-k6/* |
src/types/* |
@node/* |
src/node/* (forbidden from k6 scenarios — enforced by ESLint) |
Runtime note: scenarios run in k6's goja engine, not Node.js. There is no
fs,http,path, orurl— use k6 built-ins (k6/http,k6/ws,k6/crypto, …). Webpack bundles each scenario for thewebtarget.
Your real workloads live in their own isolated, git-ignored client directories — they never get committed to this framework repo:
clients/<your-client>/
├── config/ # Environment-specific JSON config
├── scenarios/ # k6 scenarios, organized by the 5 buckets
├── data/ # Test data (CSV/JSON/JSONL)
└── lib/ # Client-specific services & helpers
Already have the requests in Postman, Bruno or curl? Import them into the client (service class, one api/ scenario per request and a flow/ scenario that chains extracted values); the result goes through the generation gate, and a smoke must pass before any load:
node bin/import-collection.js --from=collections/shop.postman_collection.json --client=<name>
node bin/import-collection.js --from=collections/shop-bruno --bruno-env=staging --client=<name> --dry-run
node bin/import-collection.js --from=collections/shop.curl.sh --client=<name> --name=checkoutScaffold one from the reference client, or export an existing client as a standalone repo:
./bin/create-client.sh --client=<name>
./bin/export-client.sh --client=<name> --output=/path/to/repo --git-init --ci=githubFull docs are a bilingual Docusaurus site (docs-site/, EN + ES):
pnpm docs:start # English
pnpm docs:start:es # Spanish
pnpm docs:build # Static buildHighlights:
- Feature Catalog —
docs-site/docs/framework/feature-catalog.md - Load Profiles —
docs-site/docs/framework/load-profiles.md - Patterns Guide —
docs-site/docs/framework/patterns/patterns-guide.md - Metrics Engine —
docs-site/docs/framework/metrics/metrics-engine.md - Reporting —
docs-site/docs/framework/reporting/reporting.md - Security —
docs-site/docs/framework/security/security.md
pnpm build # Webpack production build
pnpm build:watch # Webpack watch mode
pnpm typecheck # tsc --noEmit
pnpm lint # ESLint
pnpm test # Vitest unit tests
pnpm validate # typecheck + lintThis project follows Conventional Commits. Use commitizen (pnpm exec cz) for guided messages; pre-commit hooks run lint-staged + Prettier.
MIT © José Castillo