QA How-To
k6 SharedArray CSV Data Parameterization Tutorial
Learn k6 SharedArray CSV data parameterization with a runnable local API, safe CSV parsing, unique iteration rows, VU mapping, checks, and failure gates.
23 min read | 3,241 words
TL;DR
Load and validate your CSV inside a k6 SharedArray callback. Select rows with scenario.iterationInTest for unique iterations, vu.idInTest for stable VU identity, or modulo for approved reuse, then verify response correctness with checks and thresholds.
Key Takeaways
- Parse CSV inside the SharedArray callback so k6 shares the resulting data across VUs.
- Validate headers, row shapes, and duplicate IDs before sending requests.
- Use scenario.iterationInTest for one row per iteration when the dataset covers all starts.
- Use vu.idInTest for a stable identity per virtual user.
- Use modulo only when the operation explicitly allows record reuse.
- Gate correctness with checks and thresholds, then verify the server echoed the intended row.
k6 SharedArray CSV Data Parameterization lets you load a CSV once for a k6 test and choose a specific record for each iteration or virtual user. This tutorial builds a complete local example: a synthetic CSV, a small API, a SharedArray loader, three row-selection policies, and commands that prove each policy works.
The distinction between loading and selecting matters. Sharing parsed rows reduces duplicate data held by VUs; it does not decide whether two requests may reuse the same account. You will make that decision explicitly, then check the result in the server response and k6 output.
Use synthetic records and a service you control while learning. A production data file can expose personal information in source control, logs, exported metrics, or a failed request trace. The k6 performance engineering guide covers workload planning beyond this focused data tutorial.
What You Will Build
- A local HTTP endpoint that accepts a synthetic order and returns the selected user ID.
- A CSV file with eight test identities and product codes.
- A k6 script that parses that file inside the
SharedArraycallback and validates its shape before traffic begins. - A unique-per-iteration mode, a stable-per-VU mode, and a deliberate cycling mode.
- Checks and thresholds that distinguish response correctness from mere HTTP completion.
All commands assume a shell on your machine. The example uses Node.js standard-library APIs for the target and k6-provided APIs for the load script. No third-party CSV package or remote demo service is needed.
Prerequisites
Install Node.js and k6, then record their exact installed versions with node --version and k6 version. Use the current k6 documentation for your installed release; this tutorial uses k6/data, k6/execution, k6/http, check, scenarios, and thresholds. The official SharedArray reference and execution context reference describe those APIs. Because releases change, this guide does not invent a pin or assume the reader's exact local version.
On macOS, the package-manager install is:
brew install k6
node --version
k6 version
If Node.js is absent, install a supported release from its official distribution for your platform and rerun the commands. A containerized k6 installation also works, but a container's localhost refers to the container, so adapt the API address and mount both load.js and users.csv. Keep the first run native to avoid mixing data errors with networking errors.
You need a free local port 3000, a terminal for the API, and another terminal for k6. Check the port before starting if another project normally uses it. The sample requests are intentionally small; they demonstrate data ownership, not a meaningful capacity limit.
Step 1: Create the workspace and verify the tools
Create a dedicated directory so the CSV, script, and local service stay together. k6 resolves the relative open('./users.csv') path from the script location, so this layout makes the later command predictable.
mkdir -p k6-csv-lab
cd k6-csv-lab
node --version
k6 version
pwd
Verify: Both version commands print an installed version and pwd ends in k6-csv-lab. Write the exact two versions in your run notes when comparing results with another engineer. If k6 version reports command not found, fix the installation before making test data; a CSV tutorial cannot diagnose a missing runner.
The shell's current directory matters when you create the files below. If you open a second terminal, run cd k6-csv-lab there too. Prefer a repository with these two files committed as a pair when you adapt the example, since a script without its synthetic fixture cannot be reproduced in CI.
Step 2: Create a small, auditable CSV fixture
Create eight records. The first column is a stable synthetic identifier, the second is a non-deliverable example address, and the third is the product code the local API will echo. The data deliberately has more rows than the default four-iteration smoke run, so you can observe unused records before testing exhaustion.
cat > users.csv <<'CSV'
user_id,email,sku
u001,user01@example.test,SKU-A
u002,user02@example.test,SKU-B
u003,user03@example.test,SKU-C
u004,user04@example.test,SKU-D
u005,user05@example.test,SKU-A
u006,user06@example.test,SKU-B
u007,user07@example.test,SKU-C
u008,user08@example.test,SKU-D
CSV
wc -l users.csv
head -n 2 users.csv
Verify: wc -l reports nine lines, including the header. The first two displayed lines show the exact header and u001 record. A trailing newline is normal and must not create a ninth data object.
This fixture avoids quoted fields to keep human inspection easy, but the parser in Step 4 handles quoted commas and doubled quotes too. It rejects a malformed quote rather than silently shifting columns. That behavior matters when real data contains display names or descriptions: a naive line.split(',') can pair a password or user ID with the wrong record.
Do not put real credentials in this file. For authenticated load, provision disposable test identities through an approved process and supply credentials from a protected store. Review the dataset's lifecycle, cleanup, and reuse limits before running a longer profile. The JMeter CSV Data Set Config guide provides a useful comparison if your team also runs JMeter.
Step 3: Start a local API that exposes the chosen row
Create server.mjs. It accepts JSON at POST /orders, validates the fields relevant to this lesson, and echoes the selected identity. The response makes row selection observable without relying only on k6 logs. This is a teaching target, not a mock of a production order service.
import { createServer } from 'node:http';
const server = createServer((request, response) => {
if (request.method === 'GET' && request.url === '/health') {
response.writeHead(200, { 'content-type': 'application/json' });
response.end(JSON.stringify({ status: 'ok' }));
return;
}
if (request.method !== 'POST' || request.url !== '/orders') {
response.writeHead(404);
response.end();
return;
}
let raw = '';
request.setEncoding('utf8');
request.on('data', chunk => { raw += chunk; });
request.on('end', () => {
let order;
try {
order = JSON.parse(raw);
} catch {
response.writeHead(400);
response.end('invalid JSON');
return;
}
if (!/^u\d{3}$/.test(order.userId ?? '') ||
!/^[^@]+@example\.test$/.test(order.email ?? '') ||
!/^SKU-[A-D]$/.test(order.sku ?? '')) {
response.writeHead(422);
response.end('invalid order fields');
return;
}
response.writeHead(201, { 'content-type': 'application/json' });
response.end(JSON.stringify({
accepted: true,
userId: order.userId,
sku: order.sku
}));
});
});
server.listen(3000, '127.0.0.1', () => {
console.log('Local API listening on http://127.0.0.1:3000');
});
Save the block as server.mjs, then start it in the first terminal:
node server.mjs
Leave that terminal running. In the second terminal, enter the workspace and check the health route:
cd k6-csv-lab
curl -i http://127.0.0.1:3000/health
Verify: The server prints its listening message and curl returns HTTP 200 with {"status":"ok"}. A connection refusal means the process is not running or port 3000 is unavailable. A 404 means you reached a different service or mistyped the route. Resolve that before adding k6, because otherwise transport errors will obscure the data-selection behavior.
The API does not persist orders. That keeps repeated tutorial runs deterministic. When you replace it with a real service, account for side effects: order creation may require unique request IDs, inventory cleanup, rate limits, and deletion of test artifacts.
Step 4: Build k6 SharedArray CSV Data Parameterization
Save the complete block below as load.js. It parses CSV text in init context, converts each row into an object, checks header and duplicate IDs, and returns an array from the SharedArray callback. The parser covers commas inside quoted fields, doubled quotes, CRLF, and a final newline. It treats an unterminated quoted value as an error.
import http from 'k6/http';
import { check } from 'k6';
import { SharedArray } from 'k6/data';
import exec from 'k6/execution';
function parseCsv(text) {
const rows = [];
let row = [];
let field = '';
let quoted = false;
for (let i = 0; i < text.length; i += 1) {
const char = text[i];
if (quoted) {
if (char === '"' && text[i + 1] === '"') {
field += '"';
i += 1;
} else if (char === '"') {
quoted = false;
} else {
field += char;
}
} else if (char === '"') {
if (field !== '') throw new Error('Quote inside unquoted CSV field');
quoted = true;
} else if (char === ',') {
row.push(field);
field = '';
} else if (char === '\n') {
row.push(field);
rows.push(row);
row = [];
field = '';
} else if (char !== '\r') {
field += char;
}
}
if (quoted) throw new Error('Unterminated quoted CSV field');
if (field !== '' || row.length > 0) {
row.push(field);
rows.push(row);
}
return rows;
}
const users = new SharedArray('synthetic users', function () {
const records = parseCsv(open('./users.csv'));
const header = records.shift();
if (!header || header.join(',') !== 'user_id,email,sku') {
throw new Error('Expected CSV header user_id,email,sku');
}
if (records.length === 0) throw new Error('CSV has no data rows');
const ids = new Set();
return records.map((columns, index) => {
if (columns.length !== 3 || columns.some(value => value === '')) {
throw new Error('Invalid CSV row ' + (index + 2));
}
const [userId, email, sku] = columns;
if (ids.has(userId)) throw new Error('Duplicate user_id: ' + userId);
ids.add(userId);
return { userId, email, sku };
});
});
const mode = __ENV.MODE || 'unique';
const vus = Number(__ENV.VUS || 2);
const iterations = Number(__ENV.ITERATIONS || 4);
const apiUrl = __ENV.API_URL || 'http://127.0.0.1:3000';
if (!['unique', 'vu', 'cycle'].includes(mode)) {
throw new Error('MODE must be unique, vu, or cycle');
}
if (!Number.isSafeInteger(vus) || vus < 1 ||
!Number.isSafeInteger(iterations) || iterations < 1) {
throw new Error('VUS and ITERATIONS must be positive integers');
}
if (mode === 'unique' && iterations > users.length) {
throw new Error('Unique mode needs at least one CSV row per iteration');
}
if (mode === 'vu' && vus > users.length) {
throw new Error('VU mode needs at least one CSV row per VU');
}
export const options = {
scenarios: {
orders: {
executor: 'shared-iterations',
vus,
iterations,
maxDuration: '1m'
}
},
thresholds: {
checks: ['rate==1'],
http_req_failed: ['rate==0']
}
};
export default function () {
let index;
if (mode === 'unique') {
index = exec.scenario.iterationInTest;
} else if (mode === 'vu') {
index = exec.vu.idInTest - 1;
} else {
index = exec.scenario.iterationInTest % users.length;
}
const user = users[index];
if (!user) throw new Error('No CSV row for index ' + index);
const response = http.post(
apiUrl + '/orders',
JSON.stringify(user),
{
headers: { 'content-type': 'application/json' },
tags: { operation: 'create_order' }
}
);
const valid = check(response, {
'order accepted': result => result.status === 201,
'correct user returned': result => {
try {
return result.json('userId') === user.userId;
} catch {
return false;
}
}
});
if (!valid) {
console.error('Order failed for ' + user.userId +
' with status ' + response.status);
} else {
console.log('selected ' + user.userId +
' for iteration ' + exec.scenario.iterationInTest);
}
}
Verify: With the API still running, execute k6 run -e MODE=unique -e VUS=2 -e ITERATIONS=4 load.js. The summary reports four iterations, eight successful checks, and zero failed HTTP requests. The four selected lines may arrive in a different order, but they refer to u001 through u004 exactly once each.
The placement of open('./users.csv') is deliberate. Grafana's SharedArray documentation explains that parsing before the callback can create a copy per VU and lose the expected memory benefit. The callback must return an array. Accessing an element later returns that element to the requesting VU, so avoid copying the entire collection into a normal array during every iteration.
This script uses a small custom parser to keep the tutorial self-contained. For full CSV dialect support or very large files, evaluate Grafana's documented CSV module or a vetted parser for your installed k6 release. Compare behavior for quoted newlines, delimiters, encodings, and file size before changing the loader. The underlying selection policies remain the same.
Step 5: Give each iteration a distinct row
The default mode maps exec.scenario.iterationInTest directly to an array index. That property is zero-based and unique within this scenario's test execution, including distributed execution, although distributed indexes can have gaps. The script checks that the configured iteration count fits the dataset before requests start.
Run all eight rows:
k6 run -e MODE=unique -e VUS=3 -e ITERATIONS=8 load.js
Verify: The summary shows eight completed iterations and 16 successful checks. Search the small console output for each u001 through u008. Their order is not guaranteed because the three VUs schedule independently. The fact that a particular VU sends a particular row is also not guaranteed: the mapping belongs to the iteration, not the worker.
Test the exhaustion guard intentionally:
k6 run -e MODE=unique -e VUS=3 -e ITERATIONS=9 load.js
Verify: k6 rejects the configuration with Unique mode needs at least one CSV row per iteration before generating the intended workload. Return to eight or fewer iterations for the successful path. This explicit failure is safer than indexing beyond the array and sending an undefined identity, and safer than silently wrapping when account reuse violates the test's data contract.
The unique mapping fits one-time tokens, one-use coupons, account creation, or records whose state changes permanently after use. It is less suitable for a duration-based scenario because the total number of starts depends on service speed. When you switch executors, revisit the data policy rather than carrying this finite index rule forward blindly. See the k6 scenarios and executors guide for how iteration counts differ across workload models.
Step 6: Compare stable VU assignment with intentional cycling
A long-running virtual user may need the same account for every journey, especially when a session token or cart state belongs to that user. exec.vu.idInTest is one-based and test-wide unique, so subtract one for a zero-based CSV index. The shared-iterations executor does not promise an equal number of iterations per VU, but each VU that runs will keep its assigned row.
k6 run -e MODE=vu -e VUS=2 -e ITERATIONS=8 load.js
Verify: The selected IDs are drawn only from u001 and u002. One may appear more often because faster VUs claim more shared iterations. Eight iterations and 16 successful checks are still expected. Do not interpret the distribution as a guarantee that each VU completed four iterations; use a per-VU-iterations executor if that exact count is the workload requirement.
For read-only searches or other operations where reuse is approved, cycle by the test-wide iteration index:
k6 run -e MODE=cycle -e VUS=2 -e ITERATIONS=16 load.js
Verify: Each of the eight IDs appears twice, with 16 completed iterations and 32 successful checks. The modulo operator makes reuse explicit. The local API permits it, so this is a valid tutorial run; a one-time registration API would make the same policy wrong.
| Policy | Index expression | Suitable data contract | Main risk |
|---|---|---|---|
| Unique per iteration | scenario.iterationInTest |
One record consumed by one operation | Finite data must cover planned starts |
| Stable per VU | vu.idInTest - 1 |
One identity retained across a VU's work | Enough rows must exist for all VUs |
| Cycle | scenario.iterationInTest % users.length |
Explicitly reusable records | Shared accounts may collide in server state |
These policies are not interchangeable with __VU or __ITER in distributed work. Grafana's execution context reference describes which IDs are unique across a test and which are local to an instance or VU. If multiple scenarios share one file, decide whether their row spaces may overlap. A test-wide VU ID can span scenarios, while an iteration index is unique in its scenario; design partitioning accordingly.
Step 7: Prove failures are visible in the gate
A successful HTTP transport does not prove the selected row produced the correct business result. The script checks both HTTP 201 and the echoed userId. The checks threshold requires every check to pass; http_req_failed requires no failed request. These strict values are appropriate for this local fixture and should be replaced with approved service objectives for a real performance run.
Temporarily point the same script at an unused local port:
k6 run -e MODE=unique -e VUS=1 -e ITERATIONS=1 \
-e API_URL=http://127.0.0.1:3999 load.js
Verify: The request fails, the order accepted and correct user returned checks fail, and the threshold result is unsuccessful. Restore the default endpoint by omitting API_URL on the next run. This is a controlled failure test; do not use a real external service as a negative target.
There are two different signals here. check() records boolean samples and keeps the script moving. A threshold evaluates aggregate metrics and makes the run fail when the criterion is violated. Without the threshold, a red check in the summary might not stop a CI pipeline. The k6 thresholds and checks tutorial covers how to set tolerances for larger, variable workloads.
For a real test, tag the operation with a stable label such as create_order, as this script does. Avoid putting userId, email, or a unique order ID into metric tags. High-cardinality tags inflate storage and can expose test identities. The console.log line is a small-run teaching aid; remove or sample it before any meaningful load, because per-iteration logging can burden the generator and bury failure evidence.
Step 8: Verify k6 SharedArray CSV Data Parameterization
Run a final eight-row pass and capture the summary:
k6 run -e MODE=unique -e VUS=2 -e ITERATIONS=8 load.js
Verify: Confirm eight iterations, 16 passed checks, no failed HTTP requests, and no threshold failure. Compare that summary with the API terminal: the local server remains available and curl -i http://127.0.0.1:3000/health still returns 200. If a run ends early because of a time limit or interrupted process, do not claim all configured rows were exercised.
When adapting the script, start by writing a data contract: what does one CSV row represent, may it be reused, can two concurrent requests use it, and who cleans up its server-side state? For unique data, count planned starts and reserve enough rows. For VU-bound sessions, size the file for maximum allocated VUs, not the average active VUs. For cycling, verify that reuse cannot create artificial locking, stale tokens, or duplicate-operation errors. Preserve the CSV header validation so a changed fixture fails before traffic.
Memory savings are one reason to use SharedArray, but do not report a fabricated multiplier. Measure generator resident memory with the same k6 build, VU count, dataset, and host, comparing a loader that shares data with one that duplicates it. The parser itself still does work during initialization, and large row objects still cost memory when accessed. For huge files, compare the current experimental CSV facilities documented by Grafana with your workload's access pattern; streaming is a different design because arbitrary row lookup and repeatable per-VU assignment are harder.
Once local behavior is proven, point API_URL at an authorized test service and replace the synthetic fixture through an approved provisioner. Add authentication without printing tokens. Correlate k6 checks and request metrics with service logs and traces, then confirm that the generator delivered the intended operation mix. The k6 load testing tutorial explains the broader path from smoke run to a defended load profile.
Troubleshooting
Problem: open() cannot find users.csv -> Put the file beside load.js or update the relative path inside the SharedArray callback. Check the path from the script's location and include the file when packaging the script for CI.
Problem: The loader rejects the header or a row -> Inspect the first line, column count, blank cells, and duplicate user_id values. A spreadsheet export may add a byte-order mark or use a semicolon delimiter; normalize the export intentionally instead of weakening validation without review.
Problem: Unique mode reports too few rows -> Lower ITERATIONS or provision enough distinct records. Modulo is only a fix when reuse is allowed by the business operation; it is not a substitute for one-use identities.
Problem: The server connection is refused -> Start node server.mjs and check curl before k6. If k6 runs in Docker, its 127.0.0.1 is inside that container; use a reachable host address and mount the script and CSV.
Problem: Checks fail even though the endpoint returns a response -> Inspect the HTTP status and echoed userId. A 422 from this API means the CSV value did not match its field rules; a 404 means the route or base URL is wrong. Keep response logging bounded and avoid dumping sensitive bodies.
Problem: Records appear out of order or one VU repeats an ID -> Out-of-order completion is normal under concurrency. Inspect the selected policy: unique mode keys on test-wide iteration, VU mode holds one row per worker, and cycle mode deliberately reuses rows. Assess the guarantee you need, not the printed order.
Interview Questions and Answers
A practical explanation of this design starts with data ownership, then covers indexing, failure behavior, and measurement. The interview questions below are also provided in the structured Q&A field for practice.
Q: Why place open() inside the SharedArray callback? The callback is the work k6 shares. Opening and parsing before it may allocate a full copy in each VU runtime, defeating the memory objective.
Q: Which execution identifier gives a row to one iteration? exec.scenario.iterationInTest is a zero-based unique index within the scenario's test execution. Check that its possible range fits the fixture.
Q: How do you reserve one identity for a VU? Use exec.vu.idInTest - 1 as an array index, with a guard for the highest allocated VU ID. That identity remains associated with the VU even when iteration assignment changes.
Q: Why can a modulo data policy be dangerous? It silently reuses records. That is valid for approved read-only data but can cause duplicate writes, account contention, or token invalidation in stateful flows.
Q: What happens when a check fails? k6 records a failed check sample. The run's exit status is governed by threshold criteria, so add an explicit checks threshold when correctness must gate automation.
Q: Can SharedArray guarantee unique accounts by itself? No. It shares storage; the script's selection rule determines which VU or iteration reads each element. Uniqueness also depends on the dataset and on any cross-scenario or cross-run reuse.
Q: How would you verify this at scale? Confirm data provisioning and partitioning, compare planned versus completed iterations, watch generator CPU and memory, and inspect service-side effects. Run a small traceable sample before increasing load.
Common Mistakes
- Parsing the CSV into a normal array before constructing
SharedArray, which can duplicate work and memory. - Splitting each line at every comma, which corrupts quoted fields.
- Treating a cycling index as unique just because the first pass has no repeats.
- Assuming shared-iterations distributes work evenly across VUs.
- Printing every email, token, or payload to logs during a load run.
- Measuring only response latency while incorrect rows or failed business operations go unnoticed.
- Reusing a dataset across parallel CI jobs without accounting for collisions and cleanup.
Where To Go Next
Keep the local fixture as a fast regression for row selection. Then expand the test in one direction at a time: add a documented authentication flow, introduce a business-safe data provisioner, or move to a scheduled load profile with server-side observability. For distributed execution, plan how each load generator receives the same fixture and how test-wide identifiers map to records; the k6 distributed load testing guide develops that deployment concern.
If you work across tools, compare this design with JMeter CSV Data Set Config. The key question remains the same across runners: who owns each data row during concurrent work, and what proves the service used the intended row? Once you can answer that from a small verified run, increase workload only within an approved test environment.
Conclusion
K6 SharedArray CSV data parameterization is a two-part design. Parse and validate the file once in init context so VUs can access shared records, then choose an index that matches the operation's reuse rule. The runnable local example demonstrates unique iterations, stable VU identities, deliberate cycling, and a threshold that fails when the selected record does not produce the expected response.
Your next action is to run the eight-row unique case, provoke the controlled failure, and write the data contract for the first real service you intend to test. Keep the fixture synthetic until that contract includes provisioning, concurrency, cleanup, and evidence.
Interview Questions and Answers
What problem does SharedArray solve in k6 CSV parameterization?
It stores the returned array once in shared memory rather than creating the full parsed collection independently for every VU. I load and parse inside its init-context callback and return an array. Row selection remains a separate concern.
Why is open() outside the SharedArray callback a mistake?
It can read and parse the file separately in VU runtimes before the shared callback is reached. That can erase the memory benefit I expected. I keep the file read and transformation inside the callback.
Which identifier supports a unique row per iteration?
exec.scenario.iterationInTest is zero-based and unique for iterations in that scenario's test execution. I index the array directly and check the planned count against its length. In distributed runs I also account for possible gaps in assigned indexes.
How do you bind a CSV row to a virtual user?
I use exec.vu.idInTest - 1 because VU IDs start at one and array indexes start at zero. I size the dataset for the maximum allocated VUs and check for missing rows before or during execution.
When is modulo selection appropriate?
Modulo makes a finite dataset cycle as iterations increase. I use it only when repeated and potentially concurrent use of the same record is part of the test contract. It is wrong for one-use credentials or operations with duplicate-write constraints.
How do checks and thresholds work together in this example?
The checks assert HTTP 201 and the echoed user ID for each request. Their samples alone do not guarantee a failing process exit. The checks threshold requires all samples to pass, while the http_req_failed threshold catches transport and protocol failures.
How do you validate a CSV fixture before a load run?
I check the exact header, number of columns, empty values, duplicate IDs, and the required number of rows. Then I run a small traceable sample and compare the selected IDs with the API response. I never wait for a large run to reveal malformed data.
What would you monitor before claiming SharedArray saved memory?
I would compare generator resident memory under the same k6 build, dataset, VU count, and host with shared and nonshared loaders. I would also watch CPU, completed iterations, and errors so a memory reduction does not hide a changed workload.
Frequently Asked Questions
Does k6 SharedArray parse CSV automatically?
No. SharedArray shares an array returned by its callback; your code still has to parse CSV into records. This tutorial uses a local parser, while Grafana also documents CSV facilities whose availability should be checked against your installed k6 release.
Where should open() go when loading a CSV with SharedArray?
Put open() inside the SharedArray callback in init context. Opening and parsing before the callback can create copies per VU and lose the intended memory benefit.
How do I give each k6 iteration a unique CSV row?
Index the shared array with exec.scenario.iterationInTest and require enough rows for the planned iteration count. Check exhaustion before generating traffic rather than silently wrapping.
How do I keep one CSV account assigned to each VU?
Use exec.vu.idInTest - 1 as the zero-based row index and provide enough rows for the maximum VU ID in the test. The VU can then reuse its account across its own iterations.
Can k6 reuse CSV records after reaching the final row?
Yes, a modulo expression can cycle through rows when reuse is permitted. Do not use it for one-time tokens, registrations, or stateful accounts that cannot safely handle concurrent reuse.
Will a failed k6 check fail CI?
A check records pass or fail samples but does not by itself define the process outcome. Add a threshold on checks, such as rate==1 for this local deterministic fixture, when a failed check must fail the run.
How should I handle CSV files in distributed k6 runs?
Ensure each generator can access the intended fixture and use execution identifiers with test-wide semantics for uniqueness. Also account for gaps, multiple scenarios, parallel jobs, and shared server-side state.
Related Guides
- Export k6 Traces to OpenTelemetry: k6 Export Traces OpenTelemetry Tutorial
- JMeter CSV data set config (2026)
- k6 Environment Variables (__ENV) Tutorial
- k6 handleSummary HTML Report Tutorial
- k6 Test Server Sent Events Streams: Load Testing Tutorial
- Mask Production Data Preview Environments: A Safe Tutorial