A Rookie's Guide to HLD: Design Zomato with Nouns and Verbs
How to approach any high-level design interview: extract the data model and APIs from plain sentences — nouns, verbs, hidden tables — applied live to a Zomato-style food delivery system design.
The interviewer smiles, opens the whiteboard, and says: "Design a food delivery app — something like Zomato." Forty-five minutes. The marker is in your hand. And your mind is a perfectly blank page.
Here's the thing nobody told you, and it changes everything: you never invent the data model or the APIs — you extract them from the requirements. Nouns become your data model. Verbs become your APIs. Once that clicks, every design question stops being a creativity test and becomes a fill-in-the-blanks exercise. This article is the recipe, run live on Zomato, step by step — and by the end, you'll see why the famous boxes-and-arrows part comes last, not first.
Let's start nowhere near a computer
Think about how an architect designs your house. They don't sit alone inventing rooms. They interview you: "We cook every day. The kids do homework at a table. Grandparents visit for months." Then they extract — cooking daily means a real kitchen, homework means a study nook, visiting grandparents means a ground-floor bedroom. The house was hiding inside your sentences all along; the architect's skill is pulling it out.
A design interview is exactly this, and the panic comes from doing it backwards — trying to invent a system from nothing instead of extracting it from sentences. So we'll get the sentences first. Here's the whole recipe before we run it:
Seven steps, every one mechanical. Let's go.
Step 1 — Write 3–5 plain sentences: "A _ can _."
Don't skip this, and don't rush it — everything else is extracted from these sentences. For Zomato:
- A customer can browse nearby restaurants.
- A customer can view a restaurant's menu.
- A customer can place an order with multiple items.
- A customer can track the order's status.
- A restaurant can accept and update an order.
Notice what you just did: you scoped the problem out loud. No payments yet, no delivery partners, no reviews — and saying that to the interviewer ("I'll start with this core and extend later") is itself a senior move.
While these sentences say what the system does, spend one breath on how well it must do it — the non-functional requirements: low latency on browsing, high availability, strong consistency where money and orders are involved, durability so a placed order is never lost, and room to scale. You don't design for these yet; you just name them, because every box you draw later has to earn its place by serving one of them. (This is the beat that turns a feature list into a system, and it's the one rookies skip most.)
Step 2 — Circle the nouns. Each noun = a table.
From our sentences: Customer (call it User), Restaurant, MenuItem, Order. Four nouns, four tables.
Unsure whether something is a table or just a column? If it has its own attributes or its own lifecycle, it's a table; if it's a single value, it's a column. "Address" is a column when a user has one — and a table the moment users can save several.
Step 3 — Find the hidden nouns.
Read sentence three again: an order with multiple items. An order contains many menu items; a menu item appears in many orders. That many-to-many relationship can't live inside either table — the relationship is itself a table:
This is the #1 thing rookies miss, so make it a reflex: likes, follows, bookings, enrollments, cart contents — all hidden nouns. The smell test: if you're tempted to store a list inside a column, that list is a missing table.
Step 4 — Fill every table with the same 5-part checklist.
No creativity needed here either. Every table gets: (1) an id, (2) foreign keys to whatever it belongs to, (3) its actual content fields, (4) a status column if the thing has a lifecycle, (5) timestamps.
users (id, name, phone, created_at)
restaurants (id, name, lat, lng, is_open, created_at)
menu_items (id, restaurant_id → restaurants, name, price, is_available)
orders (id, user_id → users, restaurant_id → restaurants,
status, total_amount, created_at, updated_at)
order_items (id, order_id → orders, menu_item_id → menu_items,
quantity, price_at_order)Two details in there that interviewers genuinely reward:
price_at_order. Menu prices change next week; your receipt from today must not. Anything that has to be "frozen in time" gets snapshotted into the child table. Spot this out loud and watch the interviewer's pen move.
That status column is secretly a machine. It's not a free-text field — it's a fixed set of states and legal moves between them:
Every arrow is a business rule ("only the restaurant can move PLACED → ACCEPTED"), which sets up the auth story in the next step.
Step 5 — Circle the verbs. Each verb = an API.
Back to the sentences: browse, view, place, track, accept/update. The grammar of REST is simple — URLs contain only nouns (plural); the HTTP method is the verb: create → POST, read → GET, update → PATCH, delete → DELETE. Odd verbs like "cancel" or "follow" become a POST/PATCH on a sub-resource.
GET /restaurants?lat=..&lng=..&page=1 browse nearby (paginated)
GET /restaurants/{id}/menu view the menu
POST /orders place an order
body: { restaurant_id, items: [{ menu_item_id, qty }] }
GET /orders/{id} track status (auth: order owner)
PATCH /orders/{id}/status update status (auth: that restaurant only)
body: { status: "ACCEPTED" }Two add-ons you should attach automatically, without being asked: every list endpoint gets pagination (the day you have 10,000 restaurants is the wrong day to discover this), and every write endpoint must answer "who is allowed to call this?" — the status machine above already told you the answers.
Step 6 — Trace every sentence through your design.
This is your safety net, and it's mechanical: take each Step 1 sentence and walk it through the tables and endpoints.
"A customer places an order" → POST /orders → server checks each menu_item exists and is_available → inserts one row in orders (status PLACED) plus N rows in order_items — in a single transaction, because half an order is worse than no order → returns the order id.
If any sentence can't complete its walk, you're missing a column, a table, or an endpoint — and you found out in minute twenty, not from the interviewer's raised eyebrow.
The trace is also your answer to "walk me through what happens when…" — which is the question interviewers always ask next. You've already rehearsed it.
Step 7 — Only NOW do you draw the boxes.
Most rookies start here and drown. You're ending here, and the boxes draw themselves — because for every endpoint you ask exactly one question: read-heavy or write-heavy? That same question also picks your datastore, and naming which store and why is exactly what the NFRs were for:
- Browsing restaurants and menus: massively read-heavy → a relational database for the source of truth, with a cache (Redis) in front to serve the latency NFR.
- Placing orders: writes that must not be half-done → the relational database, with transactions, because the consistency and durability NFRs leave no choice.
- Tracking status: the client polls
GET /orders/{id}for v1; mention push/websockets as the upgrade.
The rule of thumb worth saying out loud: relational when you need transactions, a cache like Redis for hot reads, counters, and TTLs, a wide-column store when writes outscale a single primary. Pick the one the NFR demands, then justify it in a sentence.
That's a defensible v1 on the whiteboard: client → load balancer → service → database, cache on the read path. Nothing exotic — and every piece is there because the data model demanded it, which is exactly the justification interviewers are listening for.
Now every HLD concept has somewhere to live
Here's the real payoff, and it's bigger than Zomato. Every HLD topic you've ever read about floats uselessly in your head until there's a skeleton to bolt it onto. You now have the skeleton — so go implement the rest, one concept at a time:
- Rate limiting — protect
POST /ordersfrom abuse at the gateway. You can build that box properly: Designing a Rate Limiter. - Queues — "notify the restaurant of a new order" doesn't belong in the request path; an order-events queue decouples it.
- Search —
GET /restaurants?q=biryanieventually outgrows SQLLIKE; that's a search index bolted onto the same table. - The scaling ladder — you never jump straight to sharding. You climb: one database → add a cache → add read replicas → shard the writes → migrate hot tables to a specialized store. The read/write split from Step 7 tells you which rung you're on and what to reach for next.
- Websockets — upgrade order tracking from polling to push, now that you know precisely which endpoint it replaces.
- What happens when a component fails — the question interviewers love and rookies forget. Walk each box and answer it: if the cache dies, fail open to the database (slower, still correct); the database survives a node loss because a replica is ready to fail over; a flaky downstream call gets a timeout plus an idempotent retry, which is why
POST /ordersshould be safe to retry. A design that degrades instead of collapsing is what turns a working v1 into a senior one.
Pick any one, ask "where does it attach to my skeleton?", and design it in. That question — not memorizing fifty architectures — is what HLD practice actually is. Every HLD article on this site walks these same beats end to end; Designing a Movie Ticket Booking System is a worked example you can read alongside this recipe.
Where to go from here
The recipe, on a card: sentences → nouns → hidden nouns → 5-field checklist → verbs → trace every sentence → boxes last. Follow it robotically and you will always land a defensible v1, which you can then refine out loud.
- Test yourself right now. Take a problem you've struggled with — BookMyShow, Uber, Splitwise — and run Steps 1–3 alone. (Splitwise's hidden noun is delicious.)
- Zoom in. The same recipe at class level — nouns → classes, verbs → methods, status → state machine — is the LLD interview, and it has its own guide: A Rookie's Guide to LLD.
- See a full concept built end-to-end on a skeleton like yours: Designing a Rate Limiter.
Next time a whiteboard marker lands in your hand, you won't be inventing anything. You'll be circling nouns — and the system will be hiding inside the sentences, right where it always was.