Load Testing with k6: Verifying Magento Store Scalability
AI generated
PASS
expect()
Load Testing · k6
Load Testing with k6: Verifying Magento Store Scalability
How a Grafana k6 script delivers a solid answer to how many concurrent users a Magento store actually tolerates before response times tip over

A functional E2E test confirms that a checkout completes correctly for a single, isolated user, but says nothing about what happens once two hundred users run through the same checkout at the same time. That gap is exactly what load testing with k6, an open-source, script-based load testing tool, closes by simulating realistic, concurrent user load and delivering precise metrics on response time, error rate, and throughput, well before a real sale rush exposes those limits painfully in production.

16 min read k6 Load Testing

1. Why functional tests alone don't verify scalability

A classic E2E test with Playwright or Cypress only confirms that a single, isolated test run completes correctly, but says nothing about how the same application behaves once hundreds of users simultaneously hit the same server, the same database, and the same shared resources. A Magento checkout that finishes in 800 milliseconds in a single test run can climb to several seconds or fail entirely under concurrent load through database locks, exhausted connection pools, or overloaded PHP-FPM worker processes, behavior that isolated functional tests simply can't surface.

Load tests close exactly that gap by deliberately simulating many concurrent virtual users and systematically measuring at what load level response times become unacceptable or error rates climb. For a Magento store this insight is especially valuable ahead of predictable load spikes, say a Black Friday sale or a major marketing campaign, since it lets capacity limits be known and addressed in advance, instead of discovering them painfully live under real customer traffic.

k6 has established itself in this space as a widely used, developer-friendly tool, since test scripts are written in plain JavaScript, fit seamlessly into existing development and CI workflows, and don't require heavyweight, separate infrastructure like older load testing tools.

2. Fundamentals: virtual users, iterations, and stages

A k6 script defines a flow that every virtual user (VU) repeatedly executes, while the configuration determines how many virtual users are active concurrently and how that number changes over time. Stages let load ramp up gradually, hold at a plateau, and taper off again, producing a more realistic load profile than an abruptly constant load from the start.

Every iteration of a virtual user typically runs through a sequence of HTTP requests reflecting a real user path, say opening a category page, adding a product to the cart, and submitting an order, plus short, realistic think times between steps, so the simulated load doesn't end up artificially denser than real user behavior.


import http from 'k6/http';
import { check, sleep } from 'k6';

export const options = {
  stages: [
    { duration: '2m', target: 50 },   // ramp up to 50 VUs
    { duration: '5m', target: 50 },   // hold plateau
    { duration: '2m', target: 200 },  // simulate a spike
    { duration: '3m', target: 200 },
    { duration: '2m', target: 0 },    // ramp down
  ],
};

export default function () {
  const res = http.get('https://shop.example.com/catalog/shoes.html');
  check(res, {
    'status is 200': (r) => r.status === 200,
    'response under 1500ms': (r) => r.timings.duration < 1500,
  });
  sleep(Math.random() * 3 + 1);
}

3. A realistic checkout scenario as a script

The checkout process is the most business-critical load target for most Magento stores, since it combines database writes, session management, and often external payment provider calls, exactly the components most likely to become a bottleneck under concurrent load. A load test script for checkout therefore typically models the full chain of filling the cart, choosing a shipping method, choosing a payment method, and placing the order, instead of repeating just a single, isolated request.

It's important to correctly carry session cookies and CSRF tokens between the individual requests of a virtual user, since Magento requires a valid, consistent session for many checkout steps, and a script without correct session propagation just produces error responses that don't reflect actual load capacity at all.


import http from 'k6/http';
import { check, sleep } from 'k6';

export const options = {
  scenarios: {
    checkout: {
      executor: 'ramping-vus',
      startVUs: 0,
      stages: [
        { duration: '3m', target: 100 },
        { duration: '5m', target: 100 },
        { duration: '2m', target: 0 },
      ],
    },
  },
  thresholds: {
    http_req_duration: ['p(95)<2000'],
  },
};

export default function () {
  const jar = http.cookieJar();

  const cartPage = http.get('https://shop.example.com/checkout/cart/');
  check(cartPage, { 'cart loaded': (r) => r.status === 200 });
  sleep(1);

  const shippingRes = http.post(
    'https://shop.example.com/rest/V1/carts/mine/shipping-information',
    JSON.stringify({ addressInformation: { shipping_method_code: 'flatrate' } }),
    { headers: { 'Content-Type': 'application/json' } }
  );
  check(shippingRes, { 'shipping set': (r) => r.status === 200 });
  sleep(1);

  const orderRes = http.post(
    'https://shop.example.com/rest/V1/carts/mine/payment-information',
    JSON.stringify({ paymentMethod: { method: 'checkmo' } }),
    { headers: { 'Content-Type': 'application/json' } }
  );
  check(orderRes, { 'order placed': (r) => r.status === 200 });
  sleep(2);
}

4. Defining thresholds objectively

Without clearly defined thresholds, judging a load test result stays subjective and contestable, since it's unclear at what point a measured response time counts as "too slow". k6 solves this through thresholds, objective success criteria set directly in the test configuration, say that 95 percent of all requests must stay under two seconds or that the error rate must remain below one percent.

If a test run violates a defined threshold, k6 exits the process with a non-zero exit code, letting load tests be wired into a CI pipeline automatically, exactly like functional tests: a build only counts as passed once both the functional tests and the defined load thresholds have been met, instead of treating load tests as purely manual, interpreted supplementary information.

5. Integration into the CI pipeline

A full load test with hundreds of virtual users running for several minutes rarely belongs in every single pull-request build, since it consumes time and compute capacity unsuited for fast developer feedback. In practice, a tiered model establishes itself instead: a small, fast smoke load test with a handful of virtual users runs on every merge into the main branch, while a more comprehensive load test with realistic user counts runs automatically on a daily basis or before every production deployment.

Actually running it in the CI pipeline just takes a single call to the k6 binary with the respective script, whose results can additionally be forwarded as structured JSON or InfluxDB output to a monitoring dashboard, letting load trends be tracked across multiple releases instead of viewing each test result in isolation.


# .gitlab-ci.yml excerpt
load_test_smoke:
  stage: test
  image: grafana/k6:latest
  script:
    - k6 run --vus 10 --duration 30s tests/load/checkout-smoke.js
  only:
    - merge_requests

load_test_full:
  stage: test
  image: grafana/k6:latest
  script:
    - k6 run --out json=results.json tests/load/checkout-full.js
  artifacts:
    paths:
      - results.json
  only:
    - schedules

6. Typical load targets in the Magento frontend

Besides checkout, category pages with their layered navigation and product search rank among the most load-demanding areas of a Magento store, since both depend on expensive, dynamic database queries or Elasticsearch requests, while static content like CMS pages usually gets served entirely through the full page cache or a CDN and is thus considerably less critical under load.

For a Hyva frontend it also holds that most of the server-rendered HTML is already fully present on the initial page load, so load tests should focus primarily on server response time rather than client-side JavaScript rendering, an important difference from frontend architectures relying on extensive client-side hydration.

7. Interpreting results correctly

A common interpretation mistake is looking only at the average response time, since a good average can easily hide individual but genuinely noticeable outliers for real users. Percentile values like p95 or p99 are more informative, showing how bad the response time actually gets for the slowest five or one percent of all requests, since exactly those slowest requests shape the actually perceived user experience the most.

Equally important is watching the error rate over the course of the test: a sudden, marked rise in failed requests starting at a specific number of concurrent virtual users often marks the point where a concrete resource, say the database connection pool or the maximum number of PHP-FPM workers, gets exhausted, giving a concrete starting point for targeted capacity planning instead of vague guesswork.

8. Distributed load generation for very large user counts

A single k6 process on a single machine eventually hits physical limits, usually well before the application under test itself gets overloaded, since generating thousands of concurrent HTTP connections itself consumes considerable CPU and network resources on the load generator side. For load tests with several thousand virtual users, a single test machine therefore often no longer suffices without the measured results getting skewed by the load generator's own capacity limits.

k6 solves this through distributed execution, where multiple k6 instances on different machines run the same script in parallel and direct their load jointly against the same target application, either self-orchestrated across multiple container instances or via the commercial k6 Cloud service, which handles this distribution automatically. For most Magento stores, a manageable number of parallel load generator instances already suffices to credibly recreate realistic sale scenarios involving several thousand concurrent users, without the test infrastructure itself becoming the bottleneck.

9. k6 test types at a glance

The table below compares common k6 test configurations for different purposes.

Test type Typical configuration Purpose
Smoke load test 5 to 10 VUs, 30 seconds Fast CI check on every merge
Standard load test 50 to 100 VUs, several minutes Verify realistic everyday load
Stress test Ramping up to the failure point Determine the capacity limit
Spike test Sudden jump to a high VU count Simulate a sale rush

Mironsoft

E2E test strategy, CI integration, and stable test suites

Test suites that actually find bugs instead of just blinking red?

We review existing E2E test suites for flakiness, missing test isolation, and inefficient CI runtimes, then build a test strategy that genuinely creates confidence instead of just checking a box.

Test Audit

Systematically uncovering flaky tests, testing pyramid gaps, and coverage blind spots.

CI Optimization

Building parallel execution, retry strategies, and fast feedback loops.

Cypress/Playwright Setup

Setting up robust E2E suites for Magento frontends from the ground up.

10. Summary

Load Testing with k6: The Essentials at a Glance

Core idea

k6 simulates many concurrent virtual users and objectively measures when response times tip over.

Primary target

The Magento checkout, since it combines database writes and session management.

Objectivity

Thresholds define fixed, automatically checkable success criteria instead of subjective judgment.

CI integration

Tiered model of a fast smoke load test per merge and a more comprehensive test daily or before deployments.

11. FAQ: Load Testing with k6: The Essentials at a Glance

1What is k6 typically used for?
For script-based load tests that simulate real, concurrent user load on an application.
2What language are k6 scripts written in?
Plain JavaScript, which makes integration into existing development workflows easier.
3What is a virtual user in k6?
A simulated client that repeatedly runs through the flow defined in the script.
4What are thresholds in k6 for?
They define objective, automatically checkable success criteria like maximum response times or error rates.
5Should every pull request trigger a full load test?
No, a small smoke load test is enough there, more comprehensive tests run daily or before deployments.
6Why is checkout the most important load target?
Because it combines database writes, session management, and external payment services.
7Why are percentile values more informative than the average?
Because they show how bad the slowest requests actually get, instead of hiding outliers.
8Are static CMS pages critical for load testing?
Usually less so, since they get served via full page cache or CDN and barely load the server.
9What does a sudden rise in the error rate indicate?
Often a concrete exhausted resource such as the database connection pool or PHP-FPM workers.
10Does k6 require its own heavyweight infrastructure?
No, the binary runs standalone and can be used directly in CI environments.