Latency measured on an idle screen lies. You run the integration suite, see 80 ms responses, and ship. Real users hit the API with hundreds of concurrent connections, a cold cache after deploy, and a database pool smaller than the traffic. Load testing runs production-like load in staging and turns latency into a number the team defends. k6, from Grafana, writes the scenario in JavaScript and fails the build once the number crosses the agreed line.

A scenario that mirrors traffic

Ramp stages replace an instant spike: 2 minutes up to 50 virtual users, 5 minutes at plateau, 2 minutes down. Think time between steps spreads calls the way people read screens. Load data comes from a generator pointed at staging with a distribution close to production, where a small slice of searches carries most of the traffic. A scenario with round numbers and a uniform distribution produces pretty latency that production never delivers.

Thresholds that fail the build

A threshold turns expectation into a rule: http_req_duration: p(95)<400 and http_req_failed: rate<0.01. k6 fails the run when it violates them; CI fails along. Checks validate the contract per response, with status and payload schema. The Google SRE Book (O'Reilly, 2016) treats latency and errors as SLIs; the k6 threshold is that SLI automated before any signed SLA exists.

k6 in the pipeline

A GitHub Actions job installs k6, runs the script, and publishes the result as an artifact. A short regression scenario, 2 minutes on the critical checkout path, joins every merge. A long capacity scenario runs every week. xk6 extensions add Prometheus output when the team wants graphs beyond the CI report. John Allspaw, in The Art of Capacity Planning (O'Reilly, 2008), argues for testing the load of forecast growth alongside today's load.

Saturation point and what to watch

RPS climbs with VUs until a ceiling; after that, latency spikes and RPS flattens. That ceiling lives in the database connection pool, before it lives on application CPU. You watch connection queue, pool usage, and p99 latency during the test, and tie the script to a per-request trace ID so every spike turns into an investigation. A scenario without observability becomes a stray number nobody can explain in the review meeting.