Your app is live and healthy: shipped, monitored, running without you babysitting it. Now it is growing, more users and more data arriving at once, and something in it will buckle first. That part is almost never the one you would guess. This chapter gets you to find the one real limit before you change a single line.
15.1.1A bottleneck caps the whole system
A bottleneck is the single slowest part that caps everything around it, the narrowest point in the pipe. Water moves only as fast as the tightest section allows, no matter how wide the rest of the pipe is.
Your app works the same way. A request that touches ten parts is only as fast as its slowest one. The system's real speed is set by that single part, not by the average of the parts. The same goes for its throughput, how much work it can handle at once.
15.1.2One ordinary server goes further than you think
Get the scale straight before you touch any of this. One modest server with a well-indexed database routinely serves hundreds of requests a second, which is millions a day, far more traffic than most products ever see.
So if you have a few hundred or a few thousand users and something feels slow, you are almost certainly not out of capacity. You have one slow query, and the heavier moves later in this part are insurance you buy at a size you can measure, not imagine.
15.1.3Measure before you optimize
The rule that saves you the most wasted effort: never guess at what is slow. Slowness rarely lives where it feels like it does, so a day spent speeding up the wrong part moves nothing. You met this rule tuning page speed; at scale it governs the whole system, not one screen.
The part that buckles under load is usually invisible from the outside: a database query, not the code you stare at. So measure first: put the app under realistic load, many requests at once, not the single idle click you test by hand. That is the same load-test tool from the testing part, k6, pointed at the slow path instead of at your launch peak.
On a live app you often do not need to simulate anything. The real traffic is already hitting you, so read where the time goes from the traces and logs you already have from making the app observable. Only synthesize load when you need to push past what today's users produce.
15.1.4Find the slowest part
Three tools turn "it feels slow" into a number. A profiler breaks a single request into timed spans and shows how long each part took. Simple timing does the same by hand. The slow query log is the database's own record of every query that ran too long, and it is where scale problems hide most often.
Run one and you get something like this:
One span dominates. The 814 ms query is the bottleneck; everything else is rounding error. You are not guessing anymore, you can see it.
15.1.5Fix the one that matters
Fix that one query and nothing else. It is tempting to tidy the render step or the auth check while you are in there. But do the math: make everything except the 814 ms query twice as fast, and you save a handful of milliseconds out of eight hundred.
Rule of thumb: speeding up anything but the bottleneck barely changes the total. Finding it beats optimizing on instinct every time.
Then measure again. The bottleneck does not vanish, it moves: fix the query and the next-slowest part becomes the new ceiling. Repeat until the app is fast enough for the load you have, then stop.
The rest of this part is how you fix each kind of bottleneck you find; this prompt finds the first one without letting your agent guess:
Do this now: pick the one page or action your users call slowest, paste the prompt, and let your agent measure where the time actually goes before you change a single line.