Writing k6 Scripts
Every Straden script is a folder on disk with a script.js entry point. You can create it with the Test Agent, edit it with the Script Agent, or write it yourself in the built-in editor. Straden runs it with the bundled k6 v2.0.0.
The minimum script
JAVASCRIPTimport http from 'k6/http' import { check, sleep } from 'k6' const BASE = __ENV.TARGET_URL export const options = { vus: 10, duration: '1m', thresholds: { http_req_failed: ['rate<0.01'], http_req_duration: ['p(95)<500'], }, } export default function () { const res = http.get(`${BASE}/health`) check(res, { 'status is 200': (r) => r.status === 200 }) sleep(1) }
Requirements checked by validation:
- Imports from
k6/http. - Exports a
defaultfunction. - Uses
check()assertions. - Declares load profile and thresholds in
export const options. - Passes
k6 inspect.
TARGET_URL
The test's target URL is injected as the TARGET_URL environment variable. Always build requests from __ENV.TARGET_URL rather than hard-coding a host, so the same script works when you change the target.
Scenarios
Straden encourages one scenario per script, which keeps runs comparable over time.
JAVASCRIPT// load-test/script.js export const options = { scenarios: { load: { executor: 'ramping-vus', startVUs: 0, stages: [ { duration: '2m', target: 50 }, { duration: '5m', target: 50 }, { duration: '1m', target: 0 }, ], gracefulRampDown: '30s', }, }, thresholds: { http_req_duration: ['p(95)<400', 'p(99)<1000'], checks: ['rate>0.99'], }, }
| Type | Purpose | Typical shape |
|---|---|---|
| Smoke | Does it work at all? | 1–2 VUs, 30s |
| Load | Expected traffic | Ramp to normal VUs, hold 5–15m |
| Stress | Where does it break? | Keep ramping past normal |
| Spike | Sudden bursts | Jump from low to very high VUs |
| Soak | Leaks over time | Normal load for hours |
Straden reads the options before each run and stores the resolved config (VUs, duration, stages) with the run.
Straden reads
optionswith a lightweight parser to drive the progress bar. It understands a literalexport const options = { … }with numericvus/iterationsand quoted durations ('30s','5m','1h'), including the sum ofstages. Options built dynamically still run fine in k6. The progress bar just can't estimate them.
Multi-file scripts
Split helpers into modules inside the script folder:
load-test/
├── script.js
├── lib/
│ └── auth.js
└── data/
└── users.json
JAVASCRIPTimport { login } from './lib/auth.js' const users = JSON.parse(open('./data/users.json'))
Thresholds and run status
k6's exit code decides the result. If every threshold passes the run is passed; if any threshold fails it's failed (exit 99). Straden adds p(99) to the summary trend stats, so p(99) thresholds work out of the box.
setup() and teardown()
k6 kills setup() and teardown() after 60 seconds by default — and the target is often still saturated when teardown runs. If they make HTTP requests:
JAVASCRIPTexport const options = { setupTimeout: '3m', teardownTimeout: '5m', } export function teardown(data) { // Batch cleanup in bounded chunks instead of one request per item for (let i = 0; i < data.ids.length; i += 50) { http.batch(data.ids.slice(i, i + 50).map((id) => ['DELETE', `${__ENV.TARGET_URL}/items/${id}`])) } }
A teardown timeout after an otherwise clean run is reported as passed with a warning.
Good practice
- Add realistic
sleep()think time between requests. - Name checks descriptively — they show up in the summary and insights.
- Tag requests (
{ tags: { name: 'GET /products/:id' } }) so dynamic URLs group together. - Prefer
check()overconsole.log; console output goes to the run log and is noisy at scale.