Engineering4 min read

Performance & Load Testing

Measure and validate system performance with k6 - load tests, stress tests, performance thresholds, and identifying bottlenecks under realistic traffic.

Performance Testingk6Load TestingStress TestingWeb Vitals

skill: Performance & Load Testing category: Engineering tags: [Performance Testing, k6, Load Testing, Stress Testing, Web Vitals] readingTime: 4

Performance testing prevents embarrassing outages on launch day. The goal isn't maximum load - it's understanding where your system degrades. Run load tests in staging with production-like data and realistic user behavior. The worst load test is one that doesn't match how real users use the system.

Workflow

  1. Design realistic load scenariosLoad tests that hit one endpoint in a loop don't reflect real user behavior. Realistic scenarios mix read/write operations, include think time, and distribute traffic across endpoints proportionally to production.
  2. Interpret k6 results and identify bottlenecksRaw metrics (requests/second, latency percentiles) tell you what's slow but not why. Pairing k6 output with APM (Datadog, New Relic) or profiling identifies the bottleneck.
  3. Run stress and spike testsLoad tests verify normal capacity; stress tests find the breaking point; spike tests verify the system handles sudden traffic bursts and recovers gracefully.
  4. Profile frontend with Core Web VitalsFrontend performance directly affects conversion rates. Google's Core Web Vitals (LCP, CLS, INP) are the standardized metrics for user experience.
  5. Integrate performance tests in CIPerformance regressions are invisible without automated checks. CI integration fails the build when p95 latency or error rate exceeds thresholds - before code reaches production.

Output Format

Performance: k6 stages ramp-up/hold/spike with thresholds (p95<500ms, error_rate<1%), stress test doubling VUs to find break point, web-vitals LCP/INP/CLS measurement, and Lighthouse CI budget enforcement.

k6 stages: ramp to 50 VU → hold 5m → spike to 200 → ramp down
thresholds: { "http_req_duration": ["p(95)<500"], "http_req_failed": ["rate<0.01"] }
onLCP/onINP/onCLS + sendToAnalytics for real-user monitoring
Lighthouse CI: minScore:0.9 performance, maxLCP:2500ms
GitHub Action: k6-action → exits 1 on threshold breach → PR fails

Examples

Input

Output

Edge Cases & Gotchas

  • Test data exhaustion - Load tests that create orders exhaust test inventory or generate gigabytes of data. Use a cleanup script after load tests, or design tests to read-only existing data for sustained tests.
  • DNS caching in k6 - k6 caches DNS by default - tests that should test DNS failover need dns: { ttl: "0s" } in options. Also: test from same region as production users for realistic latency.
  • HTTP/2 push-down - k6 supports HTTP/2 by default. If your server behaves differently under HTTP/1.1 vs HTTP/2, test both: options: { httpDebug: "true" } to see protocol used.
  • Correlation between VU count and real user count - k6 VUs are persistent connections with no think time by default. 100 VUs ≠ 100 concurrent users. With 2s think time per request, 100 VUs ≈ 50 requests/second, not 100.

When to Break These Rules

  • Use Gatling instead of k6 for teams with Java expertise - Gatling's Scala/Java DSL integrates naturally with JVM-based test suites and has better HTTP/2 and WebSocket support.
  • Use distributed load testing (k6 cloud, Locust on Kubernetes) instead of local k6 when traffic needs to simulate global distribution or exceed 50K RPS from a single machine.

Reference Files

  • https://k6.io/docs/
  • https://web.dev/vitals/

More skills in this library

Browse all technical skills - Mobile, AI/ML, Web, Backend, Design, and Product.