Performance is the one production problem you’re almost guaranteed not to see before launch — because you test with tiny data. The app is instant with the twenty rows you created by hand, so it looks done. Then real users arrive, the tables grow, and the same code that felt fast starts timing out. Here are the patterns that cause it and how to catch them while the fix is still cheap.
Why it’s fine now and won’t be
A query that does something silly per-row is invisible at small scale. Ten rows, ten silly operations — nobody notices. Ten thousand rows, ten thousand silly operations — the page hangs and the database strains. The cost was always there; it just scaled past the point where you’d see it.
The N+1 query
The classic. You load a list of 50 items, then for each item run another query to fetch its author, or its count, or its tags. That’s 1 + 50 queries to render one page. With AI-generated code it’s everywhere, because looping and “just fetch it inside the map” reads naturally. The fix is to fetch related data in one query (a join, an in (...), or your ORM’s batched include).
Missing indexes
A query that filters or sorts on a column with no index makes the database scan every row. Fine at 100 rows, brutal at 100,000. Any column you regularly where or order by on — user_id, created_at, email — usually wants an index.
Loading everything
select * with no pagination, a feed that fetches the whole table and slices it in JavaScript, an admin page that renders every record. It works until the table is big, then it ships megabytes and melts the browser. Paginate at the database, select only the columns you use.
Doing heavy work in the request
Generating a report, resizing an image, or calling a slow third party inside the request that’s waiting on it. One user is fine; a handful at once exhausts your connections and everything queues. That work belongs in a background job.
How to check before users do
- Seed real volume. Insert 50,000 rows and click around. Problems that hide at 20 rows are obvious at 50,000.
- Count the queries. Most frameworks can log queries per request — if one page fires 60, you have an N+1.
- Run
EXPLAINon your common queries. “Seq Scan” on a big table means a missing index.
Scaling bugs are the half of production-readiness that has nothing to do with security and everything to do with whether your launch survives its own success. A seniorgrade audit covers it directly — naive queries, missing indexes, N+1s and blocking work — alongside the security read. Run the free self-check to see where you stand first.