---
name: performance
description: "Make software measurably faster and cheaper to run — measure first, find the one bottleneck, fix it, and prove the gain with before-and-after numbers instead of guessing. Use it when a page, endpoint, query, or job is slow, a hosting or database bill jumps, load times or Core Web Vitals regress, or before launching something that must handle real traffic."
license: MIT
metadata:
  author: "Gaitro"
  category: "performance"
  copyright: "Copyright (c) 2026 Farnor"
  source: "https://gaitro.com/skills/performance"
---

# Performance

Most slow software has one bottleneck, and it's rarely where you'd guess. Measure, change one thing, measure again — and keep only what the numbers support.

## Steps

1. **Define the target.** What's slow, for whom, and how fast is fast enough? "The order page loads in under a second at the 95th percentile." "The nightly import finishes in ten minutes." Without a target you won't know when to stop.
2. **Measure the current state.** Time the real path with realistic data: server timings or logs for endpoints, `EXPLAIN ANALYZE` for queries, a profiler for CPU, Lighthouse or WebPageTest for pages (LCP, INP, CLS). Record the numbers — they're your baseline.
3. **Find the bottleneck.** Look at where the time actually goes. The usual culprits:
   - **N+1 queries** — a query inside a loop; fetch everything in one query or a batch
   - **Missing indexes** — a filter, join, or sort on an unindexed column (a sequential scan of a large table)
   - **Unbounded work** — loading every row or rendering every item, with no limit or pagination
   - **Waterfalls** — requests made one after another that could run in parallel
   - **Oversized payloads** — columns and fields you don't use, large JSON, unoptimized images, heavy JavaScript bundles
   - **No caching** — recomputing or refetching what rarely changes; rendering public pages per request when they could be static or cached at the edge
4. **Change one thing** — the fix for the biggest measured cost. Prefer doing less work (fewer queries, smaller payloads, caching) over doing the same work faster.
5. **Measure again, the same way.** Compare with the baseline. If the number didn't move, revert the change — complexity without a gain is a cost.
6. **Repeat until you reach the target, then stop.** Don't optimize what doesn't matter.
7. **Keep it from regressing.** Add a guard where it's cheap: a test that counts the queries a page makes, a bundle-size budget in CI, the index in a migration, an alert on response time.

## Cost is performance too

Work you avoid doesn't only make things faster — it makes them cheaper. Caching public pages, letting idle servers sleep, batching requests, and fetching less are often the biggest savings on a hosting bill.

## Done when

- [ ] There's a stated target and a recorded baseline
- [ ] The bottleneck was found by measurement, not assumed
- [ ] Every change you kept has a measured improvement; the rest are reverted
- [ ] Behaviour is unchanged and the tests pass
- [ ] Something guards against the regression coming back

## Report back

The target, the baseline, what the bottleneck was and how you found it, what you changed, and the before-and-after numbers. Name any trade-offs — staleness from caching, extra memory — for the person to accept.

## Traps

- Optimizing before measuring.
- Testing with ten rows when production has ten million.
- Caching without a plan for invalidation — fast and wrong.
- Shaving microseconds off code while an N+1 query costs a hundred times more.
