Most advice treats scalability like an upgrade you buy later — a switch you flip once you get big. In practice it works the other way around. The decisions that determine whether your app can grow are made before anyone writes a line of code, in how you define the problem and structure the data. By the time you actually have a scaling problem, your cheapest options are usually gone.
That is not a sales pitch; it is the arithmetic of software. IBM’s Systems Sciences Institute has long documented that a flaw is cheap to fix while it lives in a design document and brutally expensive once it is running in production — the commonly cited multipliers run from roughly 1x at the design stage to 15x during testing and 60–100x after release. Zoom out and the numbers get sobering: the Consortium for Information & Software Quality (CISQ) has estimated the cost of poor software quality in the United States at around $2.41 trillion a year, of which roughly $1.52 trillion is accumulated technical debt — the interest you pay on shortcuts taken early.
Here is the part a marketing page will never tell you: most apps never need the scale their founders imagine. So the goal is not to build something that handles ten million users on day one — that is expensive over-engineering, and it can sink you before you find out whether anyone wants the product at all. The goal is narrower and more useful: avoid the specific early decisions that turn future growth into a full rewrite instead of a configuration change.
This article walks through those decisions. It is written for the person commissioning the app — the founder or product owner — so it stays plain-language, but it stays technically honest so the engineer building it wouldn’t wince.
“Make it scalable” sounds like one requirement. It is really at least five, and they pull in different directions:
Optimising the wrong axis is slow and costly. A dashboard 500 people check twice a day is trivial no matter how it’s built; a system ingesting hundreds of events per second is a genuine engineering problem. When we built Incredible Years, a scalable OTT streaming app with offline playback and Android TV support, the axis that mattered was concurrency and media delivery. For NeurCloud, an AI-driven analytics platform, the pressure was data volume and query performance. For a loan-origination system like Armstrong Mortgage, transaction integrity and compliance dominated. Same word, three completely different builds.
So before anything else, pick the one or two axes that actually matter for your business over the next two to three years. That single choice shapes every decision below.
“We’ll have 10,000 users” is not a specification. What a developer needs to know is what one user does in a typical session, how often, and what the system has to do in response.
Is your app read-heavy (people mostly viewing content) or write-heavy (people constantly creating and updating)? Is traffic steady, or does it spike — a food-delivery app at dinnertime, a ticketing app at on-sale? How much data moves per action? If you can describe a realistic busy hour of usage, you’re ready to design for it. If you can’t, no amount of “make it scalable” will help, because the engineer is guessing.
This is also where good discovery earns its keep. One founder we worked with came to us with a complex backend build and a tight deadline; because the requirements were mapped carefully up front, we could respond to the timeline by allocating more resources to the work rather than cutting scope. That only worked because the shape of the work was understood before the build started — you can’t resource what you haven’t defined. (It’s the whole reason our own process starts with a discovery workshop rather than a code editor.)
Everyone specs features. Almost no one specs the qualities the app has to have while delivering them — and those are the ones that are brutal to add later.
Before you build, get explicit about: how fast key screens must load, what uptime you need, how much downtime is acceptable for maintenance, what must happen to data if the system crashes mid-operation, and which regulations apply (data privacy, data residency, payment-card rules, healthcare rules). Retrofitting compliance or security into a finished application is one of the most expensive exercises in software, precisely because it touches the data model and the architecture — the two things you least want to disturb once real users exist. A fintech product like a mortgage platform has to be built around those constraints from the first sprint; bolting them on after launch means reopening decisions you thought were closed.
If you take one idea from this article, take this: code is cheap to change, screens are cheap to change, but the structure of your core data is the single hardest thing to change once real users and real data exist.
Your key entities — users, orders, listings, messages, whatever your domain is — and the relationships between them form the foundation everything else sits on. Get them roughly right and the app can evolve for years. Get them wrong and you eventually face a migration that is part surgery, part archaeology, performed on a live system while customers are using it. A day spent getting the domain model not-wrong at the start routinely saves months later. This is where scalability quietly lives or dies, long before you ever add a server.
Here is the most practical scaling lever there is, in one sentence: if your application servers don’t hold important information in their own memory, you can run one of them or a hundred and simply add more as traffic grows.
The technical name is stateless design. It means things like user sessions and in-progress work live in a shared database, cache, or storage layer — not inside the memory of whichever server happened to handle the last request. When state lives in the app process, adding a second server breaks things, because the two servers don’t share what they know. When state lives outside, scaling becomes almost boring: you add capacity behind a load balancer and carry on. This is exactly the kind of setup a managed cloud environment such as AWS is built to support, and it’s why we lean on it for server management — but the decision to design statelessly has to be made in the architecture, not purchased afterwards.
The most common self-inflicted wound in ambitious new projects is starting with a fleet of “microservices” — many small, independently deployed services — because that’s what the big tech companies are known to use.
You are (almost certainly) not solving the problem microservices solve. Microservices exist to solve organisational problems — letting many separate teams deploy without stepping on each other — not technical ones. Their advocate Martin Fowler’s own guidance is blunt on this point: nearly every successful microservices system he’s seen began as a monolith that grew too big and was carefully broken up, and building services from scratch tends to end in trouble because you have to guess the boundaries before you understand the domain. He calls the ongoing overhead of running distributed services the “microservice premium” — a tax that only pays off past a level of complexity most products never reach.
The evidence in the wild backs this up. Shopify processes enormous transaction volume on a Rails monolith; GitHub served millions of developers the same way for years; Stack Overflow runs on a comparatively modest .NET monolith. You very likely do not have more scale than they do.
The right starting point for most custom web and mobile applications is a modular monolith: a single, cleanly deployed application with clear internal boundaries between modules, written so that if one part ever needs to become its own service, the seams are already there. You get most of the organisational upside with a fraction of the operational cost — and you keep the option without paying for the complexity.
This connects to the hardest truth in the whole piece. When CB Insights analysed why startups die, running out of capital topped the list — but they’re explicit that it’s the final symptom, not the root cause; the deeper driver was poor product-market fit, cited in around 43% of failures (the classic version of that stat, “no market need,” has hovered near 42% for a decade). In plainer terms: far more products die from building something nobody wanted than from failing to handle traffic they never got. Every month spent engineering for imaginary scale is a month not spent finding out whether the product works. Build the simplest thing that could work, get it in front of real users, and let genuine demand — not a blog post about what Netflix does — tell you when to invest in scale.
You cannot scale what you cannot see. Before launch, you need a way to answer “what’s slow, and why” in production — basic logging, response-time tracking, error rates, and database query timing.
This sounds optional. It isn’t. Teams that add observability only after their first performance crisis end up debugging blind during the exact moment visibility matters most. The instrumentation is cheap to add at the start and painful to add mid-emergency, so it belongs in the initial build, not the wish list.
The most scalable technology stack is the one your team can actually run with confidence. A “more scalable” database or framework that nobody on the team knows is a liability, not an asset — because scaling problems are operational, and they arrive at 2 a.m. For anything you’ll run for years, boring and well-supported beats trendy and unfamiliar.
Then, while you’re calm and nothing is on fire, write down your re-architecture triggers: “at roughly X active users, or Y requests per second, or when this specific screen crosses Z seconds, we revisit the architecture.” Deciding the thresholds in advance protects you from both failure modes at once — over-building for a scale you’ll never hit, and getting blindsided by one you didn’t plan for.
If you’re about to commission a custom web or mobile app, walk in with answers to these before you talk timelines:
Get those right and scale becomes a series of manageable adjustments. Skip them and it becomes a rewrite. That’s the whole difference.
At the design stage — but "worrying about it" means making a handful of reversible-by-design choices (data model, stateless architecture, a modular structure), not building for millions of users on day one. The aim is to keep future scaling cheap, not to pre-solve scale you don't have yet.
Almost certainly not at the start. Microservices solve team-coordination problems that appear at large organisational scale; for most new products they add cost and complexity without benefit. Begin with a well-structured (modular) monolith and extract services only when a real, measured pain — a genuine bottleneck or teams blocking each other — justifies it.
Disproportionately more than fixing them early. Industry research on software defects shows the cost of a fix rising by orders of magnitude from the design phase to production, because late fixes to foundational decisions (like the data model) ripple through everything built on top of them.
Vertical scaling means making one server bigger (more CPU and memory) — simple, but it has a ceiling and a single point of failure. Horizontal scaling means adding more servers and sharing the load across them — it scales much further, but only works well if your app is designed to be stateless. Which one you can use is decided by your architecture, not bought later.
Yes. Large, well-known platforms run substantial workloads on monolithic architectures. For the vast majority of custom apps, a cleanly built monolith on managed infrastructure will handle far more load than the product will realistically see for years.
Two, and they're opposites: over-engineering for scale that never arrives (usually via premature microservices), and neglecting the one genuinely hard-to-change decision — the data model. Avoiding both is most of the battle.