Test Automation

k6 Performance Testing: A Practical Guide for Product Teams

December 18, 2025 · 3 min read

Performance testing has a reputation problem. Teams think it requires expensive tools, dedicated infrastructure, and a specialist who speaks in percentiles. In reality, you can catch most performance regressions with k6, a free open-source tool, running against your staging environment in your existing CI pipeline.

Here’s how we set it up for our clients — practically, without the ceremony.

Why k6 over JMeter

We’ve used both extensively. JMeter is powerful but heavy — the GUI is clunky, test scripts are XML-based, and running it in CI requires Java and significant memory. k6 scripts are just JavaScript, they run as lightweight Go binaries, and they fit naturally into a modern CI/CD workflow.

For teams that already have JMeter suites, there’s no urgent need to migrate. But for new performance testing setups, k6 is our default recommendation. The learning curve is gentler, the scripts are readable, and the output integrates cleanly with dashboards and alerting.

Start with what matters

The biggest mistake teams make with performance testing is trying to test everything. You don’t need to load test your about page. Focus on the endpoints and flows that matter most to your users and your business.

For a typical web application, that usually means: login/authentication flow, primary data retrieval endpoints (the ones powering your main dashboard or feed), write operations (creating orders, processing payments, submitting forms), and any endpoint that talks to an external service (payment gateways, email providers, third-party APIs).

Three scenarios every app should run

Smoke test (baseline). A single virtual user running through your critical flow once. This isn’t a load test — it’s a performance baseline. If a single user experiences 3-second response times, you have a code problem, not a scaling problem. Run this on every deployment.

Load test (expected traffic). Simulate your actual expected concurrent users for a sustained period — usually 10-15 minutes. If your app serves 500 concurrent users during peak hours, run 500 virtual users and watch for response time degradation, error rate increases, and memory leaks. Run this weekly or before major releases.

Stress test (breaking point). Gradually ramp up virtual users until something breaks. The goal isn’t to hit a specific number — it’s to find your ceiling and understand how the system degrades. Does it slow down gracefully or crash hard? Run this quarterly or when your infrastructure changes.

Setting thresholds that actually mean something

k6 lets you define pass/fail thresholds, and this is where most teams either set them too loose (95th percentile under 10 seconds — that’s not a threshold, that’s a surrender) or too tight (every request under 200ms — unrealistic for most real applications).

Here’s what we typically recommend as starting points: p95 response time under 800ms for API endpoints, p95 under 2 seconds for page loads, error rate under 1%, and no requests timing out completely. Adjust these based on your actual user expectations and SLAs. The point is to have thresholds that fail your pipeline when performance genuinely degrades, not on every normal fluctuation.

CI/CD integration

The real value of performance testing isn’t running it once — it’s running it automatically on every significant change. In your CI pipeline, add k6 smoke tests after your functional E2E tests pass. If the smoke test shows a regression (response time doubled, error rate spiked), the pipeline fails before the code reaches production.

For the heavier load and stress tests, schedule them as nightly or weekly jobs rather than on every PR. They take longer to run and produce more noise in a PR-level feedback loop.

What to do with the results

k6 outputs results to stdout by default, which is fine for CI pass/fail decisions. But for trend analysis and dashboards, pipe the output to your monitoring stack. k6 integrates natively with Grafana Cloud, InfluxDB, Datadog, and Prometheus. Having a historical view of your p95 response times across deployments is how you catch gradual performance degradation — the kind that doesn’t trigger thresholds but slowly makes your app feel sluggish over months.

We’ve open-sourced our starter k6 configuration on GitHub, including the Express.js mock server we use for framework demos. It’s a good starting point if you want to see how we structure scenarios and thresholds.

  • CI/CD
  • k6
  • Load Testing
  • Performance Testing

Building something that has to hold up?

Bring the process, not a specification. We will tell you honestly whether an agent is the right answer.