Course contents

The delivery framework: from prompt to deep dives

A step-by-step system design interview framework: requirements, core entities, API, estimates, high-level design, deep dives and wrap-up, with time budgets and a worked URL shortener example.

FreeMust know for interviewsLesson13 min readBeginner → SeniorReviewed Oct 2026
On this page
  1. Picture it first: a map with time on it
  2. Step 1: Requirements (about 5 minutes)
  3. Step 2: Core entities (about 2 minutes)
  4. Step 3: API (about 5 minutes)
  5. Step 4: Estimates, only when they change a decision (0 to 3 minutes)
  6. Step 5: High-level design (about 12 minutes)
  7. Step 6: Deep dives (about 15 minutes)
  8. Step 7: Wrap-up (about 3 minutes)
  9. When the interviewer breaks the order
  10. How to say it in the interview

🗺️ What is a delivery framework?

It's a fixed order of steps you follow in every design round, so you never have to decide what to do next while also designing. Ours has seven: requirements, core entities, API, estimates (only when they matter), high-level design, deep dives and wrap-up. Think of it like a pilot's checklist: the pilot knows how to fly, but the checklist means nothing important gets skipped when things get busy.

For this lesson, we'll walk through each step with a time budget, what you should produce, and the words I'd use out loud. We'll run one small example the whole way through, a URL shortener, so you can see every step land on a real problem. The goal isn't a perfect URL shortener (that has its own page). The goal is a rhythm you can reuse on any prompt.

Below the line (out of scope)

The 30-second answer

I run every design round in the same order. First, five minutes on requirements: what the system must do, how big and fast it must be, and what's out of scope. Then the core entities and an API, so we share a vocabulary and a contract. I only do estimates when a number will change a decision. Next I draw the simplest design that satisfies every functional requirement, walking one request at a time. I spend the biggest block on two or three deep dives where the design is most likely to break. I close by naming the weak spots and what I'd do next. I check in with the interviewer between steps so they can steer.

What you’ll learn

  • Run any design round with the same seven steps and a time budget for each
  • Write functional, non-functional and out-of-scope requirements, with numbers instead of adjectives
  • Turn requirements into core entities and one API endpoint per feature
  • Decide when an estimate is worth doing: only when a number changes a decision
  • Build a high-level design one requirement at a time, then pick 2-3 deep dives with a default for each
  • Say the transitions out loud so the interviewer always knows where you are

01Picture it first: a map with time on it

The framework splits into two halves. The first 12 to 15 minutes are set-up: you're agreeing on the problem. The last 30 or so are the build: you're solving it. Most weak rounds get that ratio backwards, either rushing set-up and designing the wrong thing, or polishing set-up and never reaching the hard part.

Fig. 1

Seven steps from prompt to wrap-up, with a time budget for each

Seven steps from prompt to wrap-up, with a time budget for eachSeven numbered steps in two rows. Row one, the setup, about 12 to 15 minutes: 1 requirements, about 5 minutes, output a scope list; 2 core entities, about 2 minutes, output the nouns; 3 API, about 5 minutes, output the endpoints; 4 estimates, 0 to 3 minutes, drawn dashed because you only do them when a number changes a decision. Row two, the build, about 30 minutes: 5 high-level design, about 12 minutes, every requirement works; 6 deep dives, about 15 minutes, two or three hard problems; 7 wrap-up, about 3 minutes, weak spots and next steps. A check-in with the interviewer sits between the two rows.Set up: about 12-15 minBuild: about 30 mincheck in: "Does this scope look right?"Requirements~5 minfeatures, numbers, scope1Core entities~2 minthe nouns2API~5 minthe contract3Estimates0-3 minonly if it changesa decision4High-level design~12 minevery feature works,end to end5Deep dives~15 min2-3 hard problems,with trade-offs6Wrap-up~3 minweak spots,next steps7
Notice the dashed box and the halo. Estimates are optional and short. Deep dives get the biggest budget, because that's where most of the senior signal comes from.

The times assume about 45 minutes of design time, which is what you get in a typical 60-minute slot. In a 45-minute slot, shrink everything evenly, but protect the deep dives. Each step also has a clear output. If you can't point at the output on the whiteboard, the step isn't done.

02Step 1: Requirements (about 5 minutes)

This step turns a one-line prompt into a problem you can design against. You produce three short lists: functional requirements (what users can do), non-functional requirements (the qualities, with numbers) and out of scope (what you're deliberately not building).

Try it yourself first

Before reading on, write the requirements for "Design a URL shortener" yourself. Aim for 3 functional, 3 or 4 non-functional with numbers, and 2 or 3 things out of scope. Time-box it to 3 minutes.

Here's what I'd write on the board:

Functional (users should be able to...)

  • Create a short link for a long URL, optionally with a custom alias
  • Be redirected to the long URL when they open the short link
  • Optionally set an expiry time on a link

Non-functional

  • Redirects are fast: under 100 ms at p99, measured at our servers
  • Redirects are highly available: aim for 99.99%, which allows about 52 minutes of downtime a year
  • A short code never points to two different URLs
  • Scale: 100 million new links a day and 10 billion redirects a day (my assumption; confirm it)

Out of scope

  • Click analytics dashboards, user accounts and billing, editing a link after it's created, spam and malware scanning

Notice three things. The non-functional list has numbers, not adjectives: "fast" can't be designed against, "under 100 ms at p99" can. Second, it tells you where the pressure is. Reads outnumber writes 100 to 1, so the redirect path is the hot path. Third, the out-of-scope list protects your time. Analytics alone could fill the whole hour.

What to say: "I'll propose requirements and you tell me what to change." Proposing is faster than interrogating, and it shows product sense. Then: "Of these, I think the read latency and availability will shape the design most. Does that match your priorities?"

Where candidates slip

Many candidates write "scalable, available, reliable, low latency" and move on. That list fits every system ever built, so it tells the interviewer nothing. Pick the two or three qualities that matter most for this product, attach a number to each, and say which one wins when they conflict. For a URL shortener, availability of redirects beats strong consistency of brand-new links.

03Step 2: Core entities (about 2 minutes)

Entities are the nouns your system stores and moves around. You don't need full schemas yet, just names and a few key fields, so you and the interviewer use the same words for the next 40 minutes.

For the URL shortener:

  • Link: code, long_url, created_at, expires_at, owner_id
  • User (or API client): id, the identity that created the link

I'd add fields later, when a deep dive needs them. What to say: "These are the core entities. I'll add fields as we need them." Then move on.

04Step 3: API (about 5 minutes)

The API is the contract between clients and your system. Every functional requirement should map to at least one endpoint. If a requirement has no endpoint, either the API is incomplete or the requirement wasn't real.

POST /links
Authorization: Bearer <token>
{ "long_url": "https://example.com/very/long/path", "custom_alias": "summer-sale", "expires_at": "2027-01-01T00:00:00Z" }
-> 201 Created
{ "code": "aZ3kP9q", "short_url": "https://sho.rt/aZ3kP9q" }

GET /{code}
-> 302 Found
Location: https://example.com/very/long/path

Two small choices here are worth saying out loud, because they show you think about real behaviour. The user's identity comes from the auth token, not from a field in the body, so nobody can create links as someone else. And the redirect is a 302, not a 301. A 301 is heuristically cacheable under the HTTP spec, so browsers may stop asking you, which cuts load but means you can't change or expire a link reliably and you lose a record of the click. I'd default to 302 and revisit it in a deep dive.

What to say: "Here's one endpoint per requirement. I'm using REST because it's simple and fits create-and-read well." If you want more on the trade-offs, see API design for system design interviews.

05Step 4: Estimates, only when they change a decision (0 to 3 minutes)

Here's my rule: do the maths when a number will change a decision, and say so. Otherwise skip it and say you'll come back if a decision needs it. The URL shortener is a good case for estimates, because three numbers each drive a choice:

Question Rough maths Decision it drives
Write rate 100M a day / ~86,400 s ≈ 1,200 writes/s Modest; one well-sized database could take this
Read rate 10B a day / ~86,400 s ≈ 116,000 reads/s average, a few times that at peak Too much for one database: add a cache and many redirect servers
Total links over 10 years 100M x 365 x 10 ≈ 365 billion Sets the code length
Code length 62^6 ≈ 57 billion (too few), 62^7 ≈ 3.5 trillion 7 base62 characters is enough
Storage 365 billion x ~500 bytes ≈ 180 TB Won't fit one machine: shard the links table
Performance angle

The read-to-write ratio is the number that matters most here: about 100 reads per write. That single ratio tells you to build a separate, cache-heavy redirect path and to keep the write path simple. The exact value doesn't matter; whether it's 10:1 or 1,000:1 would change how hard you lean on caching.

What to say: "Let me do two minutes of maths, because it decides the code length and whether we need to shard." Then do it roughly, round aggressively and move on. The estimation lesson has the numbers and shortcuts.

06Step 5: High-level design (about 12 minutes)

Now you draw boxes. The goal is a design where every functional requirement works end to end, even if it wouldn't survive the full load yet. Go one requirement at a time and trace the request as you draw: "To support creating a link, the client calls the write service, which..." This keeps the design honest, because every box exists to serve a requirement.

Fig. 2

URL shortener: the high-level design after step 5

URL shortener: the high-level design after step 5A client talks to a load balancer. The load balancer sends POST /links to a write service and GET /code to a redirect service. The write service takes the next block of IDs from an ID range allocator and inserts the code to URL row in the links database. The redirect service looks the code up in a cache first and falls back to the database on a miss, then returns a 302 redirect with a Location header to the client.POST /linksID blockinsertGET /{code}lookupmiss302 + LocationClientbrowser, appLoad balancerWrite servicecreate linksID allocatorhands out rangesLinks DBcode → long URLRedirect servicethe hot pathCachepopular codes
Two paths, two shapes. The write path is simple and rare. The redirect path is the hot one, so it gets its own service and a cache in front of the database.

Here's how the URL shortener builds up:

  1. Create a link. The client sends POST /links through a load balancer to a write service. The write service gets a unique ID, encodes it as a 7-character base62 code, and inserts code -> long_url into the links database.
  2. Redirect. The client sends GET /{code} to a separate redirect service. It checks a cache first and falls back to the database on a miss, then returns a 302 with the long URL in the Location header.
  3. Expiry. The redirect service checks expires_at and returns 404 for expired links. A background job can delete old rows later; it doesn't need to be on the hot path.

Notice I split write and redirect into two services. That's not decoration: the estimates said reads outnumber writes 100 to 1, so they scale differently. I'd say that out loud, because it ties a box back to a number.

What to say: "This handles all three requirements. It won't hit 116k redirects a second yet. That's the first thing I'd like to go deep on, unless you'd prefer to start elsewhere."

07Step 6: Deep dives (about 15 minutes)

This is where you earn most of the senior signal. Pick two or three places where the design is most likely to break or where the interesting trade-off lives, and for each one: state the problem, give two or three options, pick one, and name its cost. Lead with your own list, but let the interviewer redirect you.

Deep dive 1: generating unique codes. Hashing the long URL and keeping the first 7 characters is easy, but different URLs can collide, so every write needs a check and a retry. A single global counter in the database is collision-free but makes one row a bottleneck and makes codes easy to guess. What I'd pick: an ID allocator that hands each write server a block of, say, 1,000 IDs. Servers then mint codes locally with no coordination per write. If a server crashes, we lose part of a block, which is fine in a space of 3.5 trillion. If codes must be hard to guess, I'd apply a reversible shuffle to the ID before encoding it.

Deep dive 2: making redirects fast at 116k a second. Links follow a popularity curve: a small share of codes gets most of the clicks. So a cache in front of the database will absorb most reads. Redirect servers are stateless, so I'd run many behind the load balancer and add more at peak. If the interviewer pushes further, I'd mention caching redirects at a CDN edge, with the same 301 versus 302 trade-off from the API step. See Caching for the patterns.

Deep dive 3: storing 180 TB. The access pattern is a pure key lookup by code, so a key-value store or a sharded relational database both work. I'd shard by a hash of the code so load spreads evenly, and replicate each shard so a node failure doesn't break the 99.99% target. The details live in Sharding and partitioning and Replication.

What to say: "The three riskiest parts are code generation, the redirect read path and storage size. I'll start with the read path since it carries 99% of the traffic. Is that where you'd like to go?"

08Step 7: Wrap-up (about 3 minutes)

Close the loop. Walk the requirements list once and point at what satisfies each. Then name the weakest part of your design and what you'd do with more time. This shows judgement, and it often sets up a good follow-up question.

For the URL shortener: "Every requirement is covered. The weakest part is abuse: anyone can shorten a phishing link. With more time I'd add asynchronous URL scanning and rate limiting on POST /links. I'd also add click analytics by putting click events on a queue so the redirect path stays fast." Rate limiting has its own design problem if the interviewer bites.

09When the interviewer breaks the order

Sometimes the interviewer will skip ahead ("Let's assume the API, draw me the design") or jump into a deep dive at minute 8. Go with it. The framework is there to help you, not to argue with them. Write down any requirement you haven't confirmed yet as an assumption in a corner of the board, and keep moving.

The one step I'd fight to keep, briefly, is requirements. Even 60 seconds of "Here's what I'm assuming we're building" saves you from designing the wrong system. Everything else can bend.

The same seven steps work on very different prompts. On typeahead, the entities are prefixes and suggestions and the deep dives are about latency and freshness. On a chat app, they're messages and connections, and the deep dives are about real-time delivery. The steps stay the same; only the hard parts move.

10How to say it in the interview

When I interview, the framework itself isn't what I'm scoring. What I'm scoring is a candidate who clearly knows where they are in the hour, and why. Narrate your transitions. They take five seconds each and they make you sound in control.

In the interview

"Let me start with requirements: I'll propose some and you correct me. Core features are create a short link, redirect, and optional expiry. Analytics and accounts are out of scope. Redirects need to be fast and highly available, and with 10 billion redirects a day against 100 million new links, this is a read-heavy system at about 100 to 1. My entities are Link and User, and I have one endpoint per feature. A quick estimate says 365 billion links over ten years, so 7 base62 characters is enough, and about 180 TB means we'll shard. Here's a simple design that covers every feature, with the redirect path split out. Now I'd like to go deep on code generation and the read path, since those are where it breaks first."

On the whiteboard

  • 1 Reqs (5m): functional · non-functional + numbers · out of scope
  • 2 Entities (2m): Link{code, long_url, expires_at}, User
  • 3 API (5m): POST /links · GET /{code} → 302
  • 4 Estimates (0-3m): only if they change a decision
  • 1.2k w/s · 116k r/s · 365B links → 7 chars · 180 TB → shard
  • 5 HLD (12m): every requirement end to end
  • 6 Deep dives (15m): ID blocks · cache read path · shard by code
  • 7 Wrap (3m): weakest part + next steps
Further reading (6)