Scale is a design decision, not a milestone you reach. The apps that grow gracefully made three or four ordinary choices early, and none of them were the flashy ones.
The bad news is that the same is true of the ones that seize up.
Get the data right first
Almost every problem that looks like scale is a data problem wearing a costume.
Describe the data before the screens
Write down the things your product deals with and how they relate: a member has many bookings, a booking belongs to one event. Do this in sentences before any interface exists. Changing a sentence is free. Changing a live table with real customer data in it is not.
Index what you filter and sort by
A query that runs instantly on two hundred rows can take seconds on two hundred thousand. The fix is usually one index on the column you sort or filter by. Check the slow query list before assuming anything deeper is wrong.
Never fetch in a loop
Asking the database once per row is the single most common reason a page gets slower as it succeeds. Ask once for all the rows instead.
Do the slow work later
Anything the reader does not need an answer to right now should happen in the background: sending the email, generating the file, calling the third-party service.
The reader gets an immediate confirmation, and the slow part retries on its own if it fails. It also means one slow external service stops being able to take your page down with it.
If a request waits on something you do not control, you have handed your reliability to someone else's uptime.
Cache at the edges
Cache the things that are the same for everyone and change rarely: the home page, a public list, an image. That is most of the traffic and almost none of the risk.
Be careful in the middle. A cache holding personalised data is how one reader ends up seeing another reader's information, and it is the sort of bug that is found by customers rather than by tests.
Boring choices buy you room
Pick the database, host and login provider you already understand. The interesting part of your product deserves your attention more than your plumbing does.
Choices worth keeping dull:
- —One database until it genuinely hurts.
- —One deployable application, not five services talking over a network.
- —The login provider everyone else uses, because the failure modes are documented.
The pitfalls are mostly human
The technical traps are well documented. These are the ones that actually sink projects:
- 01Splitting into services early. You trade a function call you can debug for a network call you cannot.
- 02Code with no owner. Nobody is embarrassed by it, so nobody fixes it.
- 03Dashboards nobody reads. Twelve charts and no alert is the same as no monitoring.
- 04Optimising the part that is easy to measure instead of the part that is slow.
- 05Rewriting instead of deleting. Most of the work in an old system is work that no longer needs doing.
Know what you are actually measuring
Before optimising anything, get one number: how long the common path takes for a real reader, at the slowest end rather than on average. Averages hide the readers having the worst time, and those are the ones who leave.
Start here this week
Find your slowest page and look for a query running inside a loop. That single pattern accounts for more sudden slowdowns than every architectural decision combined.
The project templates start from the data shape and the background-work pattern described here, so the boring parts are already in place.



