Irbisa · Cheatsheet

Frontend System Design

Designing a feed, autocomplete or chat, rendering strategy, API and state design, caching, offline, real-time updates, micro-frontends, build tooling

Senior Developer · 21 questions

  1. 01

    How do you structure your answer in a frontend system design interview?

    Drive the conversation in a fixed order: clarify requirements, sketch the client architecture, define the data model, agree on the API, then spend the remaining time on optimizations.

  2. 02

    What is the difference between offset and cursor pagination, and which would you use for an infinite feed?

    Offset pagination asks for items by position ("skip 40, take 20"); cursor pagination asks for "the next 20 after this item" with an opaque token from the previous page.

  3. 03

    How do you choose between CSR, SSR, SSG and ISR for the pages of a product?

    Decide per route by two questions: how fresh the content must be, and whether it has to be indexed and paint fast on a cold visit.

  4. 04

    What is a performance budget, what would you put in it, and how do you enforce it?

    A performance budget is a set of hard limits that a change may not exceed, agreed before the work starts: user-facing metrics such as LCP and INP, plus the quantities that drive them, such as JavaScript size and the number of requests.

  5. 05

    Which caching layers sit between the user and the database in a web app, and what belongs in each?

    From the user outward: the in-memory query cache, persisted storage (IndexedDB), the service worker cache, the browser HTTP cache, the CDN and the server's own caches.

  6. 06

    How would you implement infinite scroll for a long list, and what do you have to solve beyond loading the next page?

    Put a sentinel element after the last item and watch it with an IntersectionObserver; when it comes within a margin of the viewport, fetch the next page by cursor.

    import { useEffect, useRef } from 'react';import { useInfiniteQuery } from '@tanstack/react-query'; type Page = { items: Post[]; nextCursor: string | null }; export function Feed() {…
  7. 07

    How would you design an image carousel component?

    Build it on native horizontal scrolling with CSS scroll snap, load only the current slide and its neighbours, and treat accessibility and autoplay rules as requirements, not extras.

  8. 08

    How would you design an autocomplete (typeahead) search input?

    Debounce keystrokes, cancel stale requests so an old response never overwrites a newer one, cache results per query, and render the list as an accessible combobox.

    import { useEffect, useState } from 'react'; type Suggestion = { id: string; label: string }; const cache = new Map<string, Suggestion[]>();…
  9. 09

    When would you use WebSocket, Server-Sent Events or long polling for real-time updates, and how does each one work?

    Long polling holds an ordinary request open until the server has news; SSE is one long HTTP response streaming events from server to client; WebSocket upgrades the connection to a two-way message channel.

    // Long polling: the server holds each request until it has events or about 30 s passasync function longPoll(cursor = '') {  for (;;) {    try {      const res = await fetch(`/api/events?after=${encodeURIComponent(cursor)}`);      if (!res.ok) throw new Error(`HTTP ${res.status}`);…
  10. 10

    How would you design the frontend of a news feed like Facebook or X?

    Render the first page on the server for a fast LCP, then load more with cursor pagination into a normalized client cache, virtualize the list, and announce new posts with a banner instead of shifting the content.

  11. 11

    How would you design a marketplace product listing page: filters, sorting, pagination, SEO and a fast first load?

    Make the URL the single source of truth for filters, sort and page, render the first page on the server from it and cache that HTML per normalized URL, then fetch later changes on the client while the old results stay on screen.

    type Filters = Record<string, string[]>; // One filter set, one URL: one CDN cache entry and one canonicalexport function toSearch(filters: Filters, sort: string, page: number): string {  const params = new URLSearchParams();  for (const key of Object.keys(filters).sort()) {…
  12. 12

    How would you design the client of a real-time chat application?

    One WebSocket per client for events in both directions, messages sent optimistically with a client-generated id that the server echoes back, ordering by a server sequence number, and a resync from the last seen sequence after every reconnect.

    type Message = {  clientId: string; // made on the device, doubles as the idempotency key  id?: string; // assigned by the server  seq?: number; // server order within the conversation  text: string;  status: 'sending' | 'sent' | 'failed';…
  13. 13

    How would you design the API contract between a frontend and its backends: REST, GraphQL or a BFF?

    Shape the API around what screens need, not around database tables.

  14. 14

    How would you design a real-time dashboard that receives hundreds of updates per second?

    Decouple the update rate from the render rate: keep incoming data in a store outside React, coalesce updates per key, and render at most once per frame (or a few times per second), only for the widgets whose data changed.

    type Tick = { symbol: string; price: number }; // collect stream messages and hand the UI one batch per frame, not one update per messageexport function subscribeBatched(url: string, onBatch: (latest: Map<string, Tick>) => void) {  const source = new EventSource(url);  let pending = new Map<string, Tick>();…
  15. 15

    How would you make a web app offline-first?

    Serve the app shell from a service worker cache, make IndexedDB the store the UI reads from, and queue writes in an outbox that syncs when the network returns.

  16. 16

    How would you design a collaborative editor like Google Docs, where several people edit the same document at once?

    The core problem is merging concurrent edits so all copies converge: Operational Transformation on a central server, as in Google Docs, or a CRDT such as Yjs that merges in any order and works offline.

    type Insert = { pos: number; text: string; client: string }; // Shift `op` so it keeps its meaning after `applied`, a concurrent edit already appliedfunction transform(op: Insert, applied: Insert): Insert {  const before = applied.pos < op.pos || (applied.pos === op.pos && applied.client < op.client);  return before ? { ...op, pos: op.pos + applied.text.length } : op;…
  17. 17

    How would you design uploading large files from the browser: progress, cancel, retry and resume after a dropped connection?

    Upload straight to object storage through presigned URLs, split the file into parts that upload in parallel and retry on their own, report progress per part with XMLHttpRequest, and remember finished parts so a dropped connection or a reload resumes instead of starting over.

    const PART_SIZE = 8 * 1024 * 1024; // S3 parts: at least 5 MiB except the last // XMLHttpRequest, because fetch reports no upload progressfunction putPart(url: string, part: Blob, onProgress: (sent: number) => void, signal: AbortSignal) {  return new Promise<string>((resolve, reject) => {    const xhr = new XMLHttpRequest();…
  18. 18

    How would you design a design system and component library used by many product teams?

    Start from design tokens as the single source of colours, spacing and type, build accessible primitives on top, and ship them as a versioned package with documentation, visual tests and a clear contribution path.

  19. 19

    How would you handle internationalization at scale: dozens of locales, plurals, right-to-left languages and per-locale bundles?

    Keep strings out of code behind stable keys in ICU MessageFormat, format numbers and dates with Intl, load only the active locale's messages per route, and use logical CSS properties so right-to-left works by switching dir.

  20. 20

    How would you add feature flags and A/B experiments to a frontend without slowing the first render or flashing the wrong variant?

    Evaluate flags before the first render, on the server or at the edge, and ship the values with the HTML so the client hydrates with the same variant.

    import { createContext, use, type ReactNode } from 'react'; // FNV-1a hash: the same id lands in the same bucket on the server, at the edge and in the browserexport function bucket(userId: string, experiment: string): number {  let h = 0x811c9dc5;  for (const ch of `${experiment}:${userId}`) h = Math.imul(h ^ ch.charCodeAt(0), 0x01000193);…
  21. 21

    When are micro-frontends worth it, and how would you split and integrate them?

    Micro-frontends pay off when many independent teams must ship parts of one product on their own release cycles; for a single team they add cost with no benefit.