Last Minute Notes

Frontend System Design Fundamentals

How frontend system design interviews work: what is being tested, the RADIO framework with a 45 minute time budget, requirements and clarifying questions, frontend estimation (bytes, requests, DOM nodes, memory), component API design, data model and API contract, trade-off vocabulary, and how to communicate a design.

📘 Frontend System Design Fundamentals

Frontend system design asks you to design a client application or a UI component that survives real conditions: slow phones, flaky networks, large data, many teams, and users who rely on a keyboard or a screen reader. The server is usually a black box with an API you negotiate. The interesting parts are rendering, state, data flow, performance, resilience, accessibility, and how the code is organized so a team can ship it.

This page gives you the frame. The other pages fill in the technical depth, and UI Component Designs and Application Designs apply it to concrete prompts.

Table of Contents

  1. What the Interview Tests
  2. The RADIO Framework
  3. Requirements and Clarifying Questions
  4. Estimation for Frontend
  5. Architecture Styles
  6. Component API Design
  7. Data Model and API Contract
  8. Trade-off Vocabulary
  9. Communicating the Design
  10. Common Mistakes
  11. Questions

1. What the Interview Tests

FormatWhat you doMain signal
Frontend system designWhiteboard architecture for an app or widget, 45 to 60 minutes, little or no codeBreadth, trade-offs, ownership of the full client stack
UI machine codingBuild a working component in 60 to 90 minutesCode quality, state handling, accessibility, edge cases
Backend system designDesign services, storage, and scaleDistributed systems depth (see System Design)
Full-stack designBoth sides, with a rendering strategy in the middleWhere to draw the client and server boundary

What a strong answer shows:

  • Structure: you drive the conversation with a framework instead of jumping into libraries.
  • Depth on the client: rendering, state ownership, caching, networking, and the browser event loop, not only "use React and Redux".
  • Trade-offs: every choice has a cost, and you name it (SSR costs server time and hydration, optimistic updates cost rollback logic).
  • User centricity: perceived performance, accessibility, error and empty states, low-end devices.
  • Scale in the frontend sense: large data sets, large codebases, many contributors, and many deployments.

2. The RADIO Framework

RADIO is a checklist for the whole conversation.

LetterStepWhat you coverMinutes of 45
RRequirementsFeatures, users, devices, network, SEO, offline, accessibility, i18n, scale of data5 to 7
AArchitectureMajor components, rendering strategy, routing, state ownership, module boundaries8 to 10
DData modelEntities, normalized store, server state vs UI state, cache shape5 to 7
IInterfaceREST or GraphQL endpoints, pagination, error contract, real-time channel, component props and events7 to 10
OOptimizationsPerformance, accessibility, security, observability, release strategy10 to 12

Rules that keep the interview on track:

  • Write the requirements down. A visible list of in scope and out of scope items stops scope creep and shows discipline.
  • Draw before you talk. One boxes-and-arrows diagram of components and data flow anchors the discussion.
  • Go broad, then deep. Cover every letter at a high level first, then let the interviewer pick where to dive.
  • State a default and move on. "I will assume read heavy and mobile first, tell me if that is wrong" beats an open ended question.
  • Reserve the last minutes for optimizations. Candidates who spend the whole hour on the component tree miss the senior signals.

2.1 The Opening Move

A good first three minutes:

  1. Restate the problem in one sentence.
  2. Ask 5 to 8 clarifying questions (next section).
  3. Summarize the scope and the non-functional targets: "public pages so SEO matters, mobile first, p75 LCP under 2.5 s, works on a 4G connection".
  4. Name the framework you will follow, so the interviewer knows the plan.

3. Requirements and Clarifying Questions

Group your questions so they cover the decision space.

GroupQuestions to askWhy it matters
Users and scopeWho uses it, how many, anonymous or logged in, which core flows?Decides SEO, personalization, auth
PlatformsDesktop, mobile web, native wrapper, which browsers, how old?Decides APIs you can use and bundle targets
Network and deviceLow-end phones? 3G? Offline?Decides budgets, caching, offline strategy
ContentPublic or private, how often it changes, how big?Decides SSG, SSR, ISR, or CSR
DataVolume per screen, update frequency, real-time, ordering, consistencyDecides pagination, virtualization, transport
InteractionDrag and drop, rich text, keyboard shortcuts, undo, collaboration?Decides state design and conflict handling
Quality barsAccessibility level (WCAG AA), i18n and RTL, analytics, experimentsDecides component foundations
OrgHow many teams, existing design system, existing stack, release cadenceDecides modularity and deploy model

3.1 Functional vs Non-functional

FunctionalNon-functional
Post, like, comment, search, uploadLoad time, interaction latency, bundle budget
Infinite scroll, filters, sortAvailability on bad networks, offline behavior
Notifications, presenceAccessibility, i18n, browser support
Roles and permissions in the UISecurity, privacy, consent, observability

State out of scope explicitly: "I will not design the recommendation algorithm or the media transcoding pipeline, I will treat them as APIs."


4. Estimation for Frontend

Frontend estimation is about bytes, requests, memory, and main thread time, not QPS and disks. Rough numbers are enough, the point is to show you reason with them.

4.1 Network Budgets

ProfileTypical bandwidthRound tripNotes
Slow 4G (Lighthouse mobile default)about 1.6 Mbps down150 msThe common test target
Fast 4G9 to 12 Mbps70 msTypical urban mobile
Wi-Fi or fiber50 Mbps and up10 to 30 msDesktop baseline

A practical budget for an interactive mobile page is about 150 to 200 KB of compressed critical JavaScript and under 1 MB total for the first view on a mid-range phone. JavaScript costs more than its byte size: after download it is parsed, compiled, and executed on a slow CPU, and images only cost network and decode time.

// runnable
// Rough load time = round trips + bytes / bandwidth.
const profiles = {
  slow4g: { mbps: 1.6, rttMs: 150 },
  fast4g: { mbps: 10, rttMs: 70 },
  wifi: { mbps: 50, rttMs: 20 },
};

function transferMs(bytes, profile, roundTrips = 3) {
  const bitsPerMs = (profile.mbps * 1_000_000) / 1000;
  return Math.round(roundTrips * profile.rttMs + (bytes * 8) / bitsPerMs);
}

const kb = (n) => n * 1024;
for (const [name, p] of Object.entries(profiles)) {
  console.log(name, '200 KB bundle:', transferMs(kb(200), p), 'ms', '| 2 MB bundle:', transferMs(kb(2000), p), 'ms');
}

The output shows why a 2 MB bundle is a problem on slow 4G even before parse and execute time: it spends about 10 seconds on the wire.

4.2 Data and DOM Estimation

EstimateExample reasoning
Items per screenA phone shows about 5 feed posts at once, so a page size of 10 to 20 covers scrolling without waste
Payload per itemA post JSON is 1 to 3 KB, 20 posts is up to 60 KB uncompressed (about 10 to 15 KB gzipped)
DOM nodesAim under 1500 nodes on a page. A feed with 30 nodes per post at 1000 posts is 30,000 nodes, so it needs virtualization
Memory1000 posts of 3 KB is only 3 MB of JSON, but images and DOM dominate, so cap what stays in memory
Update rate500 messages per second cannot be rendered one by one, so batch to the frame rate
Request countPrefer fewer than about 10 critical requests, HTTP/2 or HTTP/3 multiplexing removes the old 6 connection limit but each request still costs latency

Use the numbers to justify choices: "the data fits in memory, so I do not need a database in the browser" or "the list can exceed 10,000 rows, so virtualization is mandatory".

4.3 Main Thread Budget

  • A frame is 16.7 ms at 60 Hz (8.3 ms at 120 Hz), and the browser needs part of it for style, layout, paint, and compositing, so your JavaScript gets roughly 10 ms.
  • A long task is any task over 50 ms. It blocks input, and many long tasks produce poor INP.
  • INP target is 200 ms or less at the 75th percentile, which means all interactions, not only the first.

5. Architecture Styles

StyleWhat it isPick when
SPA (single page app)One HTML shell, client-side routing, data over APIsLogged-in apps, rich interactivity, SEO not needed
MPA (multi page app)Server renders each page, full navigationsContent sites, simple flows, strong SEO, minimal JS
SSR + hydrationServer renders first HTML, client takes overPublic, personalized, interactive pages
Static + islandsStatic HTML with small interactive partsContent heavy sites (docs, blogs, marketing)
RSC-basedServer Components for data and layout, Client Components for interactivityFull-stack React apps wanting less client JS
Micro-frontendsIndependently deployed slices composed into one productMany teams that must ship independently
Native wrapperWeb app in a WebView or PWAReuse web code on devices, with caveats

Pick a style from the requirements, not from fashion. The deeper comparison is in Rendering and Delivery.


6. Component API Design

Many prompts are really a component (typeahead, modal, carousel, data table). The public API is part of the answer.

6.1 Principles

PrincipleMeaning
Composition over configurationAccept children and slots instead of 30 boolean props
Controlled and uncontrolledSupport both: value + onChange for control, defaultValue for convenience
Headless coreSeparate behavior and accessibility (hooks, state machines) from styles so it can be themed
Sensible defaults, escape hatchesWork with zero config, allow overriding render, class names, and refs
Accessible by defaultRoles, keyboard handling, and focus management built in, not left to the caller
Stable eventsEvent names and payloads are a contract: onSelect(item, reason)
Pure renderingRender output depends on props and state, side effects live in hooks

6.2 Example: Tabs API Sketch

// Compound components share state through context.
<Tabs defaultValue="overview" onValueChange={track}>
  <Tabs.List aria-label="Account sections">
    <Tabs.Trigger value="overview">Overview</Tabs.Trigger>
    <Tabs.Trigger value="billing">Billing</Tabs.Trigger>
  </Tabs.List>
  <Tabs.Panel value="overview">...</Tabs.Panel>
  <Tabs.Panel value="billing" forceMount>...</Tabs.Panel>
</Tabs>

What to say about it:

  • State (value) lives in Tabs, children read it from context, so layout is the caller's choice.
  • Accessibility: tablist, tab, and tabpanel roles, arrow keys move focus, Home and End jump, only the active tab is in the tab order.
  • Performance: panels render lazily by default, forceMount keeps one alive when state must persist.
  • Extension points: asChild or a render prop for custom triggers, orientation, activationMode (on focus or on click).

6.3 Component Design Checklist

  1. What are the inputs (props), outputs (events), and imperative handles (ref methods such as focus())?
  2. Which state is internal and which is owned by the caller?
  3. What are the states: loading, empty, error, partial, disabled, read-only?
  4. Keyboard map and ARIA pattern (see Security, Accessibility, and i18n).
  5. Performance at scale: how many items, how often it re-renders?
  6. Styling: tokens, theming, RTL, dark mode, reduced motion.
  7. Testing: unit, interaction, visual, accessibility.

7. Data Model and API Contract

7.1 Model the Client Data

Separate three kinds of data:

KindExamplesWhere it lives
Server data (remote, shared)Posts, users, ordersA cache keyed by query (TanStack Query, RTK Query, SWR, Apollo)
UI state (local)Open modal, draft text, selected tabComponent state, context, small store
URL state (shareable)Filters, page, sort, selected idThe URL, so links and back button work

Normalize relational data by id so one update changes every view:

type State = {
  postsById: Record<string, Post>;
  usersById: Record<string, User>;
  feedIds: string[];            // ordered ids, not copies of posts
  nextCursor: string | null;
};

7.2 Choosing the API Style

StyleStrengthWeaknessFits
RESTSimple, cacheable with HTTP, widely understoodOver and under fetching, many round tripsMost CRUD apps
GraphQLAsk for exactly the fields, one round trip, typed schemaCaching and N+1 complexity, query cost controlMany clients with different needs, nested data
BFF (backend for frontend)Server shaped for one client, aggregates servicesAnother service to ownMobile and web with different needs
tRPC or typed RPCEnd to end types in a TypeScript monorepoCouples client and server versionsInternal full-stack apps
gRPC-web or protobufCompact, typedTooling, debuggingInternal, performance sensitive
WebSocket or SSEPush updatesStateful connections to scaleReal-time (see Real-Time, Offline, and Sync)

7.3 A Good Contract

  • Pagination: cursor based for feeds (?after=cursor&limit=20), response has items, nextCursor, hasMore.
  • Errors: HTTP status plus { code, message, fieldErrors, requestId }, so UI can map codes to copy and forms to fields.
  • Idempotency: mutations carry an Idempotency-Key so retries are safe.
  • Versioning: additive changes, tolerate unknown fields, version breaking changes.
  • Conditional requests: ETag and If-None-Match for cheap revalidation.
  • Partial responses: field selection or separate summary and detail endpoints for list and detail views.
  • Time: ISO 8601 UTC timestamps, localize on the client.

8. Trade-off Vocabulary

Naming trade-offs precisely is what separates senior answers.

DecisionOption AOption BDeciding factor
RenderingSSR (fast first paint, server cost, hydration)CSR (cheap server, slow first paint)SEO, first paint, personalization
FreshnessCache aggressively (fast, stale)Always fetch (fresh, slow)Cost of stale data
UpdatesOptimistic (snappy, rollback logic)Pessimistic (simple, laggy)Risk and failure rate
TransportPolling (simple, wasteful)WebSocket (efficient, stateful)Update frequency and scale
ListsPagination (simple, steppy)Infinite scroll (smooth, memory and a11y cost)Browsing vs goal driven use
StateGlobal store (shared, boilerplate)Local state (simple, prop drilling)How many consumers
BundlingOne bundle (simple)Route splitting (fast first load, extra requests)App size
TeamsMonolith (consistent)Micro-frontends (independent, heavy)Team count and release independence
StylingCSS Modules or utility CSS (static, fast)CSS-in-JS runtime (dynamic, runtime cost)Theming needs vs performance
StorageCookie (sent to server, HttpOnly)localStorage (script readable)Security

A reusable sentence pattern: "I choose X because requirement Y, the cost is Z, and I mitigate it with W."


9. Communicating the Design

  • Start with a diagram of client, CDN, API, and real-time channel, then a component tree of the main screens.
  • Name data flows with arrows: "user action, optimistic update, request, reconcile".
  • Show states: a small table of loading, empty, error, offline, and stale for the main view.
  • Use numbers from your estimation when justifying a choice.
  • Check in: "Do you want me to go deeper on the data layer or the performance plan?"
  • Say what you would measure (LCP, INP, error rate, cache hit rate) and what would make you change the design.

10. Common Mistakes

MistakeBetter
Starting with "I will use React and Redux"Start with requirements, justify tools afterward
Designing only the happy pathShow loading, empty, error, offline, and permission states
Ignoring performance numbersGive a budget and how you would enforce it
Putting server data in a global store by handUse a server-state cache with invalidation
Forgetting accessibility until the endFold keyboard and ARIA into the component design
Over-engineering (micro-frontends for 3 developers)Choose the simplest architecture that meets the requirements
Treating the API as fixedNegotiate the contract: pagination, errors, field selection
No plan to measureName RUM metrics, error tracking, and a release strategy
Rambling without a diagramDraw early, refer back to it
Not stating trade-offsEvery decision gets a cost and a mitigation

11. Questions

Q: What is the first thing you do in a frontend system design interview? Clarify requirements: users, devices, network conditions, SEO, offline, accessibility, data volume, and team context. Then state the scope and the non-functional targets before drawing anything.

Q: How does frontend system design differ from backend system design? The constraints are the browser and the user's device: bytes over the wire, main thread time, memory, rendering strategy, accessibility, and many deployments of one client. Backend design focuses on throughput, storage, and distributed consistency.

Q: What is RADIO? Requirements, Architecture, Data model, Interface, Optimizations. It is a checklist so the conversation covers requirements through to performance, security, and observability.

Q: How do you decide between SSR and CSR? If the content is public and SEO or fast first paint matters, render on the server or at build time. If the app is behind login and highly interactive, CSR with code splitting is simpler and cheaper. Many products mix both per route.

Q: How do you estimate whether a page will be fast enough? Add the critical bytes (HTML, CSS, JavaScript, LCP image), divide by the target network speed, add round trips, then add JavaScript parse and execute time on a mid-range phone. Compare with the 2.5 s LCP target and set a bundle budget.

Q: What makes a good component API? Composition, controlled and uncontrolled modes, accessibility built in, stable events, sensible defaults, and escape hatches such as render props or asChild.

Q: Where do you store filters and pagination state? In the URL, so links are shareable, the back button works, and server rendering can read them.

Q: What would make you change your design? Measured field data (LCP, INP, error rate) or a requirement change such as a new real-time feature or an offline requirement.

Next: Rendering and Delivery.

On this page