Free lesson · Frontend System Design
"Networking is a backend thing." Said every candidate who underperforms this section.
When an interviewer steers a frontend system design round toward networking, a lot of candidates quietly relax, because they've decided networking belongs to the backend - it's servers and protocols and load balancers, someone else's department. Then they give vague, second-hand answers and wonder why the round cooled off. The misconception is understandable and it's wrong, and clearing it up is the entire purpose of this orientation lesson before we go deep on the specific technologies.
Here's the reframe. The server owns how data is produced and stored. But the entire experience of communicating with that server - choosing how the client talks to it, handling the request lifecycle, surviving a flaky connection, showing the right thing while data is in flight, recovering from failures, caching responses so you don't refetch - all of that is frontend work, and all of it is evaluated. The network is the boundary the first module kept returning to: everything on the user's side of it is yours. So networking in a frontend round isn't "do you know how TCP works." It's "do you understand how to build a robust, fast-feeling client on top of an unreliable network you don't control." That's a frontend competency through and through.
This module covers the technologies you'll choose among. This first lesson maps what's actually being assessed when networking comes up, so that as we go through HTTP versions, REST, GraphQL, gRPC, and the realtime options, you understand which interview signal each one serves.
The five things an interviewer is really checking
When networking surfaces - and it surfaces in nearly every frontend design round, because every non-trivial app talks to a server - the evaluator is checking five things. Knowing them lets you deliberately demonstrate each.
mindmap
root((Networking,<br/>evaluated))
Right communication style
REST vs GraphQL vs gRPC
Request/response vs realtime
Request lifecycle mastery
Debounce, cancel, dedupe
Loading + error + empty states
Resilience
Retries, backoff, timeouts
Offline tolerance
Performance awareness
Round trips, payload size
Caching, prefetch
Tradeoff reasoning
No free choices
Match the tool to constraints
This mind map shows the five things an interviewer evaluates when networking comes up in a frontend round. First, choosing the right communication style: REST versus GraphQL versus gRPC, and request-response versus realtime. Second, request lifecycle mastery: debouncing, cancellation, deduplication, and handling loading, error, and empty states. Third, resilience: retries, backoff, timeouts, and offline tolerance. Fourth, performance awareness: round trips, payload size, caching, and prefetching. Fifth, tradeoff reasoning: recognizing that no choice is free and matching the tool to the constraints.
1. Do you choose the right communication style?
The first signal is whether you reach for the appropriate way for the client and server to talk, rather than defaulting to whatever you've used before. Is this request/response (the client asks, the server answers) or does the server need to push updates to the client? If request/response, is REST the right fit, or does the data shape call for GraphQL, or is this an internal high-performance path where gRPC makes sense? Picking deliberately - and being able to say why - is the headline competency this whole module builds toward. Defaulting to "REST, because that's what I know" without engaging the question is the weak signal.
2. Do you master the request lifecycle on the client?
A request isn't fire-and-forget - treating it as a single await and moving on is one of the clearest junior tells. From the moment the user triggers it, there's a lifecycle: maybe debounce it (don't fire on every keystroke), maybe cancel a previous in-flight one, dedupe identical concurrent requests, show a loading state, handle the response, handle the error, handle the empty result, possibly retry. We built exactly this in the Module 0 autocomplete walkthrough - debounce, cancel, out-of-order protection. The interviewer wants to see that you treat a request as a managed lifecycle, not a single await. This is pure frontend craft and it's a strong differentiator.
3. Do you build for resilience?
The network will fail - packets drop, connections time out, the user walks into an elevator. A senior frontend engineer assumes failure and designs for it: timeouts so a request doesn't hang forever, retries with exponential backoff for transient errors (and not retrying things that aren't safe to retry), graceful degradation when offline, and clear communication to the user about what went wrong. Candidates who only describe the happy path reveal they haven't shipped to real users on real networks.
4. Are you aware of performance costs?
Everything from Module 1's first lesson applies: round trips are expensive, payloads cost transfer time, and the user is often on a slow connection. The signal here is whether you instinctively think about minimizing round trips (one request for nested data instead of a waterfall of five), keeping payloads lean (don't over-fetch), and caching so you don't refetch what you already have. Performance-awareness woven through your networking answer - not as a separate "and also performance" afterthought - reads as experience.
5. Can you reason about tradeoffs?
The meta-signal, the same one from every design lesson: there is no universally correct choice. REST is simpler but over-fetches; GraphQL is flexible but harder to cache; WebSockets are powerful but expensive to hold open. The senior move is naming what each option costs and choosing for the stated requirements. An answer that presents one option as simply "the best" misses the entire point.
The shape of this module
Everything that follows organizes around a single fundamental split in how a client and server communicate:
graph TD
Comm[Client-server communication] --> RR[Request / Response<br/>client asks, server answers]
Comm --> RT[Real-time<br/>server pushes to client]
RR --> HTTP[Built on HTTP:<br/>HTTP versions, REST,<br/>GraphQL, gRPC]
RT --> Push[Polling, Long Polling,<br/>WebSockets, SSE, WebHooks]
HTTP --> Q1{Does the server need<br/>to initiate updates?}
Push --> Q1
Q1 -->|no| RRchoice[Pick a request/response style]
Q1 -->|yes| RTchoice[Pick a realtime mechanism]
This diagram shows the structure of the module around a fundamental split in client-server communication. There are two modes: request-response, where the client asks and the server answers, and real-time, where the server pushes to the client. Request-response is built on HTTP and includes HTTP versions, REST, GraphQL, and gRPC. Real-time includes polling, long polling, WebSockets, server-sent events, and webhooks. The deciding question between them is whether the server needs to initiate updates. If no, pick a request-response style. If yes, pick a real-time mechanism.
The first half (request/response) is the default mode of the web: the client initiates, the server responds, the connection closes. We start with the transport itself - the HTTP versions and how their evolution changes your decisions - then the three dominant API styles built on top: REST (the default), GraphQL (the flexible alternative), and gRPC (the high-performance one), closing with a decision framework for choosing among them.
The second half (real-time) addresses a different need: when the server has something new and needs to get it to the client without the client asking. A chat message arrives, a stock price ticks, a notification fires. We'll walk the spectrum from faking it with repeated polling, through long polling, up to genuine push with WebSockets and Server-Sent Events, plus WebHooks for server-to-server, and finish with the canonical decision matrix for picking the right one.
The single most important question that runs through the whole module - and the one to ask first in any round - is the one in the diagram: does the server need to push, or does the client just need to fetch? Get that right and the rest of the choices narrow dramatically. We saw a preview of this exact decision in the WebSockets proof-of-concept back in the strategy phase: most "realtime" features are actually request/response in disguise.
Interview: When a design prompt involves a server, proactively classify the communication need out loud before picking a technology: "First, does this need real-time server push, or is it request/response? The feed content itself is request/response - the client fetches pages - but the 'new posts' indicator might want a push channel. Let me handle those separately." Splitting the problem along the push-versus-fetch line, before naming any specific protocol, is the move that signals you understand the landscape rather than reaching for a familiar tool.
A note on what we assume you know
We'll assume familiarity with HTTP basics - that a request has a method (GET, POST, PUT, DELETE), a URL, and headers; that a response has a status code (200, 404, 500), headers, and a body; that GET is for reading and should be safe and idempotent while POST creates and isn't. If any of that is shaky, it's worth a quick refresher, because every API style in this module is built on those primitives. What this module adds is the frontend judgment layer on top: not "what is a POST," but "given these constraints, what should the client and server actually agree to, and how do I make consuming it robust and fast." That judgment layer is the entire value of this module - the mechanics of HTTP are widely documented and easy to look up, but knowing which mechanism fits which constraint, and how to build a resilient client around it, is the hard-won part that interviews actually probe and that day-to-day frontend work actually rewards.
The five criteria applied: a worked mini-scenario
Abstract criteria are easy to nod at, so let's run them against a concrete feature the way you would in a round. Prompt fragment: "the app needs a notifications bell that shows unread count and a dropdown of recent notifications." Watch how the five criteria each generate a real design decision.
Communication style. First question: does the server need to push the count the instant a notification arrives, or is "refresh every so often" acceptable? If the product is fine with a slightly stale count, this is request/response - poll periodically - and you've avoided the cost of a persistent connection. If it must be instant (a chat-like product), you reach into the realtime half of this module. Notice this single classification decision shapes everything downstream, which is why it's criterion one.
Request lifecycle. When the user opens the dropdown, you fetch recent notifications. That fetch needs a loading state (a skeleton, not a blank box), an empty state ("you're all caught up"), and an error state. If the user closes and reopens quickly, you cancel or dedupe the in-flight request. Opening the dropdown might optimistically mark notifications as read before the server confirms. Every one of those is lifecycle craft, and naming them unprompted is the signal.
Resilience. What happens when the count fetch fails? You don't show "0" - that's a lie that hides notifications. You keep the last known count, maybe show a subtle stale indicator, and retry with backoff. What happens offline? The bell shows the last cached state rather than an error. Designing the unhappy path is where resilience is demonstrated.
Performance. The count is tiny and frequent; the notification list is larger and fetched on demand. So you separate them - poll the cheap count often, fetch the expensive list only when the dropdown opens. You cache the list so reopening is instant. You don't refetch the whole list to update one "read" flag. Each choice minimizes round trips and payload.
Tradeoffs. If you chose polling, you name its cost: it's slightly stale and it makes requests even when nothing changed. If you chose push, you name its cost: a persistent connection per user that the server must hold open. You picked deliberately for the product's staleness tolerance, and you said so.
That's one small feature generating a dozen real decisions across the five criteria. The interviewer isn't looking for the "right" notification system - they're looking for exactly this density of considered decisions, which is what the five criteria produce when you actually apply them.
The anti-patterns interviewers are listening for
It's just as useful to know the negative signals - the things that quietly mark an answer as junior, because the evaluator is listening for their absence:
- The happy-path-only answer. Describing only what happens when the request succeeds, with no mention of loading, error, empty, or offline states. Real users hit all four; ignoring them signals you've only built demos.
- Fire-and-forget requests. Treating every request as a lone
awaitwith no thought to cancellation, deduplication, or debouncing. This is what separates the Module 0 autocomplete answer (managed lifecycle) from a naive one. - The retry storm. Adding retries without backoff or limits, so a struggling server gets hammered by every client retrying in tight loops - turning a blip into an outage. Retries with exponential backoff and a cap is the mature version.
- Reaching for the heaviest tool. Defaulting to WebSockets for a feature that polling would serve, or GraphQL for simple CRUD, because it sounds sophisticated. Over-engineering is as much a red flag as under-engineering.
- Ignoring the network's hostility. Designing as if the connection is fast and reliable - no timeouts, no awareness that the user might be on 3G in a tunnel. The entire frontend premise is that the network is the user's and it's hostile.
Warning: The most common single failure in this section is the happy-path answer. It's seductive because the happy path is the interesting design work and the error handling feels like boilerplate. But to an evaluator, the error handling is where the seniority shows - anyone can describe the success case. Make a habit of, every time you describe a request, immediately following with "and if it fails or is slow, here's what the user sees." That reflex alone lifts your perceived level.
Interview: Build the classification habit until it's automatic: the moment a feature involves the server, your first spoken sentence should sort it - "Is this request/response or does it need server push? And if request/response, what's the data shape - does REST fit, or is this nested enough to want something else?" Interviewers consistently reward candidates who orient before they architect, because in real work the orientation is what prevents building the wrong thing. The technologies in the rest of this module are the answers; this classifying reflex is the question, and the question is what's actually being scored.
What you should carry out of this lesson
Networking in a frontend round is not a backend topic you can wave at - it's the assessment of whether you can build a robust, fast-feeling client on top of an unreliable network. Five things get evaluated: choosing the right communication style, mastering the client-side request lifecycle, building for resilience, staying aware of performance costs, and reasoning about tradeoffs. The whole module organizes around one split - request/response versus real-time - and the first question to ask in any round is which one the feature actually needs, because most "realtime" needs turn out to be request/response wearing a costume.
With the map in hand, we start at the foundation everything else is built on: the HTTP protocol itself, and specifically how its evolution from 1.1 to 2 to 3 quietly reshapes the optimization decisions a frontend engineer makes. That's next.