A common way to start a system design interview goes like this: the interviewer says “design a URL shortener”, and within thirty seconds the candidate has drawn a load balancer, three app servers, a Redis box and a database. It looks productive. It’s usually the moment the interview starts going badly, because nothing on the board is connected to anything the system needs to do.
Components are answers. Before you can choose them, you need the questions: who uses this, for what, how much, and what must never go wrong? Spending the first five to eight minutes on requirements isn’t a delay. It’s the part of the interview where you show you’d build the right system, not just a familiar one.
Why components come last
The same box means different things in different systems. A cache in front of a URL shortener is an easy win: links rarely change, and a stale redirect is harmless. A cache in front of an account balance is a liability, because a stale balance can approve a payment that should have been declined. You can’t tell which situation you’re in until you know the requirements.
Requirements also tell you where to spend your limited interview time. If the system is 100:1 reads to writes, the read path deserves the detail. If losing one record is unacceptable, durability and recovery deserve it. Without requirements, candidates spread their time evenly and go deep on nothing.
The first five minutes, as a conversation
Here’s an illustrative exchange for the URL shortener. The questions matter more than the specific answers, which the interviewer may simply let you choose:
Candidate: Who are the users, and what are the core actions? I’m thinking: create a short link from a long URL, and redirect when someone visits the short link.
Interviewer: Yes. Also custom aliases for logged-in users.
Candidate: Do links expire? Can they be edited or deleted after creation?
Interviewer: Default is no expiry. Owners can delete.
Candidate: Do we need click analytics? If so, how fresh?
Interviewer: Click counts per link, a few minutes delay is fine.
Candidate: Scale: how many new links a month, and how many redirects per link?
Interviewer: Say 100 million new links a month, and around 100 redirects per link.
Candidate: How fast must a redirect be, and how bad is it if redirects are down for a few minutes?
Interviewer: Redirects should feel instant. Downtime breaks every link in every email and post, so it’s bad.
That’s six questions. Notice what each one does. The first fixes the core operations. Expiry and deletion decide whether storage grows forever and whether cached redirects can go stale. The analytics question separates a feature that must be real-time from one that can be batched. The scale question feeds a quick estimate. The last one ranks availability above almost everything else.
Writing the requirements down
Write the result where the interviewer can see it, in short lines:
Functional
- Create short link (optional custom alias for logged-in users)
- Redirect short link -> long URL
- Owner can delete a link
- Click counts per link, up to ~5 min delay
Out of scope: link editing, user management, spam detection (mention, don't design)
Non-functional
- Redirect latency p99 < 50 ms server-side; availability 99.99% for redirects
- Creation can be slower and less available than redirects
- A created link must never be lost or point to the wrong URL
- Scale: 100M new links/month, ~100 redirects per linkThen a quick estimate, using the numbers just agreed. 100 million links a month is about 39 writes a second on average, roughly 120 at a 3x peak. With 100 redirects per link, reads average about 3,900 a second and peak near 12,000. At around 500 bytes per link record, that’s 50 GB a month and about 6 TB over ten years. Seven-character codes from a 62-character alphabet give 3.5 trillion possibilities, almost 300 times the 12 billion links ten years would create.
Those numbers already shape the design. Writes are small enough that one database primary could handle them. Reads are the scaling problem, and since links barely change, they cache extremely well, so a cache or CDN in front of redirects is the natural first move. 6 TB is too big to keep comfortably on one node forever, so the link store should be able to partition by short code.
Same questions, different system
Ask the same kinds of questions about a ledger for a payments app and the answers flip.
Core operations: record a transfer between accounts, show balances, show an account’s history, produce statements. Scale: perhaps 5 million transfers a day, which is about 58 a second, maybe 600 at a 10x peak. That’s tiny next to the URL shortener’s read traffic.
The non-functional answers are where it differs:
- Data loss: none. A committed transfer must survive a server or zone failure.
- Correctness: a balance may never go negative unless the account has overdraft, and every transfer must debit one account and credit another as a single unit.
- Staleness: a user’s balance must reflect their own transfers immediately; the history list can lag by seconds.
- Auditability: entries are never updated or deleted; corrections are new entries.
- Availability: high, but if forced to choose, refusing a transfer is better than recording a wrong one.
With those requirements, the design looks nothing like the shortener. A relational database with transactions, synchronous replication across zones, an append-only entries table with double-entry rows, conditional updates to stop negative balances, and idempotency keys on transfer requests. Caching balances is mostly off the table. The throughput is low enough that none of this needs exotic infrastructure, which is itself a useful conclusion.
How requirements show up in the design
A good test of your requirements phase: every requirement should leave a visible mark on the diagram. If it doesn’t change anything, either it wasn’t important or you haven’t used it yet.
| Requirement | Design consequence |
|---|---|
| Redirects at ~12,000/s peak, links rarely change | Cache or CDN in front of redirect lookups |
| Links never expire | Storage grows forever; plan partitioning by short code |
| Custom aliases | Uniqueness check on create (conditional insert) |
| Click counts within 5 minutes | Async event stream and batch aggregation, off the redirect path |
| Ledger: no committed entry lost | Synchronous replication before acknowledging |
| Ledger: no negative balances | Transaction with a conditional update, not read-then-write |
| Ledger: audit trail | Append-only entries; corrections as new rows |
Mistakes interviewers notice
Listing every feature you can imagine. Twelve features means none get designed. Pick the three to five that define the system and park the rest under “out of scope”, so the interviewer knows you thought of them.
Qualities without numbers. “Fast”, “scalable” and “highly available” can’t be designed for. “p99 under 50 ms”, “12,000 reads a second at peak” and “no more than a few seconds of data loss” can.
One consistency answer for everything. “The system is strongly consistent” isn’t a requirement. Ask per operation: redirect lookups can be stale; custom alias creation can’t allow two owners.
Collecting requirements and then ignoring them. If you learned that analytics can lag five minutes, use it: take click counting off the redirect path. Interviewers watch for whether answers feed into decisions.
Taking twenty minutes. Requirements frame the design; they aren’t the design. Five to eight minutes is usually enough, and you can return to a question later when a decision needs it.
Interview practice: a parking reservation system
“Design a system for reserving parking spaces in city garages.” What would you ask in the first few minutes, and how could the answers change the design?
Answer
I’d start with users and core operations: drivers search for garages near a location and time, reserve a space, and enter and exit; garage operators set prices and capacity. I’d confirm whether reservations are for a specific space or any space in the garage, because a specific space turns availability into a per-space booking problem, while “any space” is a counter per garage per time slot.
Then correctness: can a garage ever be overbooked? If not, reservation needs an atomic check-and-decrement on the slot’s remaining capacity, and that operation needs strong consistency even if search results can be a minute stale. I’d ask about payment (pay at booking or at exit) since that decides whether booking involves an external payment call that can time out, and about cancellations and no-shows, which affect how long a held space stays blocked.
For scale, I’d ask for the number of garages and bookings per day. A city with 500 garages and 50,000 bookings a day is a small write load, about one booking every two seconds on average, so a single relational database with transactions is plenty; the interesting work is correctness, not throughput. Finally, availability: if the system is down, can drivers still enter a garage? That points to gate devices that cache today’s reservations locally, so a backend outage doesn’t trap cars outside.