---
title: "Performance Testing: What to Measure Before You Load Test"
excerpt: "Most teams reach for load testing when the problem is a slow page for one user. Those are different questions with different tools, and answering the wrong one wastes a sprint."
metaDescription: "Performance testing explained: the types, what to measure, when load testing is the wrong tool, and where performance checks belong in CI."
publishedAt: 2026-07-30
author: Shiplight AI Team
categories:
 - Guides
 - Best Practices
tags:
 - performance-testing
 - load-testing
 - test-strategy
 - ci-testing
 - qa-process
metaTitle: "Performance Testing: What to Measure First"
featuredImage: ./cover.png
featuredImageAlt: "Illustrated Shiplight blog cover: a performance dashboard separating single-user latency from concurrent-load behavior."
---
"The app is slow" is two unrelated complaints wearing the same words. Either one user waits too long for one page, or the system falls over when many users arrive at once. The investigations share almost nothing, and starting with the wrong one is how a team spends two weeks building a load harness for a problem that was an unindexed database column.

## The types, and the question each answers

| Type | Question | When |
|---|---|---|
| Frontend performance | Why is this page slow for one user? | Continuously |
| Load testing | What happens at expected traffic? | Before a launch, periodically |
| Stress testing | Where does it break, and how? | Before a known spike |
| Soak testing | Does it degrade over hours or days? | Before long-running deploys |
| Spike testing | Can it absorb a sudden surge? | If your traffic is bursty |

**Frontend performance** is the one most teams actually need and least often measure systematically. Bundle size, render time, layout shift, time to interactive. One user, one page, no concurrency involved.

**Load testing** answers a capacity question. It is the right tool when you expect volume and need to know whether the system holds, and the wrong tool when a single request is slow, because a slow request under no load is just a slow request.

The diagnostic that separates them: **time one request with nobody else on the system.** If it is slow, that is your problem and concurrency is a distraction. If it is fast, then ask what happens under load.

## What to measure

**Percentiles, not averages.** An average hides the tail, and the tail is what users complain about. If p50 is 200ms and p99 is 8 seconds, one percent of requests are unusable and the average says everything is fine. Watch p95 and p99.

**Real user conditions.** Testing on a fast laptop on office wifi measures your laptop. A mid-range phone on a congested network is closer to the median experience for most consumer products.

**The journey, not the page.** A page that loads in 400ms inside a flow with six sequential requests is not a fast flow. Measure what the user waits for start to finish.

**Errors under load, not just latency.** A system that stays fast by dropping ten percent of requests is failing, and a latency-only dashboard shows it as an improvement.

## Where it belongs in CI

Performance regressions are much easier to prevent than to chase later, because the cause is in one recent commit rather than eighteen months of accumulation.

**Cheap and continuous:** bundle size budgets and a frontend performance check on the main routes, on every pull request. Fast enough that nobody minds. This catches the majority of regressions.

**Periodic and expensive:** load, stress and soak tests. Nightly or before a release. Running these per commit costs more than it catches.

The pattern mirrors [smoke testing](/blog/smoke-testing): a fast gate in front, an expensive suite behind it.

## The agent-era wrinkle

Coding agents produce working code quickly, and "working" does not include "efficient." Two patterns show up often enough to watch for:

**Loops that call.** An agent implementing a list view will frequently fetch per item rather than in one batched call. Correct, tested, passes review, and it turns one query into two hundred.

**Dependencies added for one function.** An agent needing a date format will add a library. Correct, and the bundle grows for a function you could have written in four lines.

Neither is caught by tests asserting correctness, because both are correct. A bundle size budget catches the second automatically. The first needs someone looking, or a query-count assertion on the paths that matter.

This is the same shape as the other agent failure we keep finding: the code does what was asked and something unmeasured got worse. See [regression risk in AI-generated code](/blog/regression-risk-ai-generated-code).

## Where functional testing sits

Performance testing tells you the system is fast. It does not tell you it is correct, and the fast path is easy to make faster by removing work that mattered.

[Shiplight](/plugins) covers the functional side: the coding agent verifies a change in a real browser through MCP and commits the check as an intent-based test that runs on every future change. Those tests catch the "we made it fast by breaking it" case that a latency dashboard shows as a win. They are not a substitute for load testing and do not measure throughput. Web applications; native mobile is not in it.

Run both. They fail in different directions.

## Frequently Asked Questions

### What is performance testing?
Measuring how a system behaves under given conditions, covering both single-user speed and behavior under concurrent load. Those are different questions with different tools.

### Is load testing the same as performance testing?
No, it is one type. Load testing answers a capacity question; frontend performance answers why one page is slow for one user, which is the more common need.

### Should performance tests run on every commit?
Cheap ones yes: bundle budgets and a frontend check on key routes. Load, stress and soak tests are periodic, because running them per commit costs more than it catches.

### What should I measure?
p95 and p99 rather than averages, on realistic devices and networks, across whole journeys rather than single pages, and error rates alongside latency.

### Why does AI-generated code cause performance regressions?
It optimizes for working rather than efficient. Per-item fetches inside loops and dependencies added for one function are both correct, pass tests, and cost real performance.

## Related Reading

- [Smoke testing](/blog/smoke-testing): the fast-gate pattern this borrows
- [End-to-end testing](/blog/end-to-end-testing): the functional layer
- [Regression risk in AI-generated code](/blog/regression-risk-ai-generated-code): the unmeasured-regression pattern
- [Quality engineering](/blog/quality-engineering): deciding which gates run where
