pencils ready ✎

System Design MCQs multiple-choice questions with answers & explanations

All 34 System Design quiz questions on one page. Pick an answer in your head, then open Show answer to check it and read why. Want a score and a timer? Take them as a quiz instead.

  1. 1.

    A search-as-you-type box sometimes shows results for 'rea' after the user has finished typing 'react', because the older request resolved last. What fixes this?

    mid
    1. AIncrease the debounce delay so requests can never overlap
    2. BCache responses in memory, keyed by the query string
    3. CAbort the previous request, or ignore responses that don't match the latest query
    4. DShow a loading spinner until every request has finished
    Show answer

    Answer: C (Abort the previous request, or ignore responses that don't match the latest query)

    Debouncing reduces how many requests you send, but any two in-flight requests can still resolve out of order. Cancel the previous one (AbortController, or RxJS switchMap) or check that a response matches the latest query before rendering it. A cache makes repeat queries faster but doesn't fix ordering.

  2. 2.

    For an autocomplete input, you want to call the API only once the user has paused typing for 300 ms. Which technique is that?

    easy
    1. AThrottling
    2. BDebouncing
    3. CMemoization
    4. DRequest batching
    Show answer

    Answer: B (Debouncing)

    A debounce waits until events stop arriving for the given time and then fires once, which suits search inputs. A throttle fires at most once per interval while events keep coming, which suits scroll and resize handlers.

  3. 3.

    In an autocomplete, keyboard focus stays in the text input while the user arrows through the suggestions. Which ARIA attribute tells assistive technology which option is highlighted?

    hard
    1. Aaria-activedescendant on the input, set to the id of the highlighted option
    2. Baria-selected="true" on the input while an option is highlighted
    3. Caria-live="assertive" on the listbox so changes are announced
    4. Dtabindex="0" on every option so each one can take focus
    Show answer

    Answer: A (aria-activedescendant on the input, set to the id of the highlighted option)

    In the combobox pattern the input has role="combobox", aria-expanded and aria-controls pointing to a role="listbox", and aria-activedescendant names the active role="option" (which also gets aria-selected="true"). Focus never leaves the input, so the user can keep typing.

  4. 4.

    Which Core Web Vital measures how quickly a page responds to user interactions?

    easy
    1. ALCP
    2. BCLS
    3. CTTFB
    4. DINP
    Show answer

    Answer: D (INP)

    Interaction to Next Paint (INP) replaced FID as a Core Web Vital in 2024. It looks at the latency of interactions throughout the visit; "good" is 200 ms or less at the 75th percentile. LCP measures loading and CLS visual stability, while TTFB is a diagnostic metric, not a Core Web Vital.

  5. 5.

    The LCP element of a landing page is a large hero image. Which change is most likely to make LCP worse?

    mid
    1. AAdding fetchpriority="high" to the hero image
    2. BAdding loading="lazy" to the hero image
    3. CServing it as AVIF or WebP at the displayed size
    4. DPreloading the hero image
    Show answer

    Answer: B (Adding loading="lazy" to the hero image)

    Native lazy loading holds the request back until layout shows the image is near the viewport, which delays the LCP. Lazy-load below-the-fold images only; the LCP image should be discoverable in the initial HTML, prioritized, and correctly sized.

  6. 6.

    Images pop in and push the text down as they load, hurting CLS. What's the standard fix?

    easy
    1. ALazy-load every image so they arrive after the text settles
    2. BConvert the images to SVG so they render instantly
    3. CInsert the images with JavaScript after the page has rendered
    4. DSet width and height (or CSS aspect-ratio) so space is reserved early
    Show answer

    Answer: D (Set width and height (or CSS aspect-ratio) so space is reserved early)

    With intrinsic dimensions the browser knows the aspect ratio and reserves the box, even with responsive CSS like width: 100%; height: auto. The same idea applies to ads, embeds and late banners: reserve their space up front.

  7. 7.

    INP is poor on a product listing: each filter click runs a 300 ms synchronous function that filters 20,000 items and re-renders. Which change most directly improves INP?

    hard
    1. APreload the web fonts so text renders sooner
    2. BPut a CDN in front of the product API
    3. CLazy-load the product images below the fold
    4. DSplit the work into chunks that yield to the main thread, or use a Web Worker
    Show answer

    Answer: D (Split the work into chunks that yield to the main thread, or use a Web Worker)

    INP measures the time from an interaction until the next frame is painted, and a long synchronous task blocks that paint. Yielding between chunks, virtualizing the list, rendering the results as a non-urgent update, or moving work to a worker all shorten the blocking time. The other options affect loading, not interaction latency.

  8. 8.

    Which Cache-Control header is best for a fingerprinted bundle like app.3f2a1c.js?

    mid
    1. Ano-store
    2. Bno-cache
    3. Cpublic, max-age=31536000, immutable
    4. Dmax-age=0, must-revalidate
    Show answer

    Answer: C (public, max-age=31536000, immutable)

    The filename changes whenever the content does, so a given URL never changes and can be cached for a year without revalidation. The HTML that references the bundles should use no-cache (store it, but revalidate every time) so users pick up new hashes right after a deploy. no-store disables caching entirely.

  9. 9.

    A CDN that supports stale-while-revalidate caches a response with Cache-Control: max-age=60, stale-while-revalidate=300. A request for it arrives 120 seconds later. What happens?

    hard
    1. AThe cached response is served with no request to the origin
    2. BThe cached response is served immediately and the CDN revalidates it with the origin in the background
    3. CThe request waits for a fresh response from the origin
    4. DThe cached copy is discarded because it is older than 60 seconds
    Show answer

    Answer: B (The cached response is served immediately and the CDN revalidates it with the origin in the background)

    For the first 60 seconds the response is fresh. Between 60 and 360 seconds (max-age plus the stale-while-revalidate window) it's stale but may be served instantly while the cache refreshes it asynchronously. After that, a blocking request to the origin is required.

  10. 10.

    Which of these does NOT protect against CSRF?

    mid
    1. ASetting session cookies with SameSite=Lax or SameSite=Strict
    2. BRequiring an anti-CSRF token on state-changing requests
    3. CChecking the Origin header on the server
    4. DMarking the session cookie HttpOnly
    Show answer

    Answer: D (Marking the session cookie HttpOnly)

    CSRF works because the browser attaches cookies to the forged request automatically; the attacker never needs to read the cookie. HttpOnly only stops JavaScript from reading it, which limits session theft via XSS but does nothing against CSRF.

  11. 11.

    An attacker manages to inject an inline <script> into your page. Which Content-Security-Policy blocks it while still allowing your own /static/app.js?

    hard
    1. Ascript-src 'self' 'unsafe-inline'
    2. Bscript-src 'self'
    3. Cdefault-src 'none'
    4. Dframe-ancestors 'none'
    Show answer

    Answer: B (script-src 'self')

    Without 'unsafe-inline', CSP blocks inline scripts and inline event handlers, and 'self' allows scripts from your own origin. default-src 'none' would block your bundle too, and frame-ancestors only controls who may embed the page. If you need specific inline scripts, allow them with a nonce or hash. CSP is defense in depth: you still escape output.

  12. 12.

    Your framework escapes interpolated text automatically. Which of these can still introduce XSS when given a comment written by a user?

    easy
    1. ARendering it with text interpolation such as {{ comment }}
    2. BAssigning it to element.innerHTML
    3. CAssigning it to element.textContent
    4. DCalling element.setAttribute('title', comment)
    Show answer

    Answer: B (Assigning it to element.innerHTML)

    innerHTML parses the string as HTML, so a payload like an img tag with an onerror handler runs attacker code. The same applies to React's dangerouslySetInnerHTML and Angular's bypassSecurityTrust* APIs. If you must render user HTML, sanitize it with a library such as DOMPurify.

  13. 13.

    An infinite-scroll feed loads ?page=3&limit=20. New posts are added at the top while the user scrolls, so they see duplicate posts. What is the fix?

    mid
    1. ACursor pagination: fetch the items after the last loaded item's id
    2. BUse smaller pages so fewer items shift between requests
    3. CRefetch every loaded page each time the user scrolls
    4. DCache each page in localStorage by its page number
    Show answer

    Answer: A (Cursor pagination: fetch the items after the last loaded item's id)

    With offsets, inserting items at the top shifts every page, so the next page repeats items (and deletions make you skip some). A cursor anchors the next page to a stable position in the ordered list, and it is also cheaper for the database than large offsets.

  14. 14.

    What is the recommended way to decide when to load the next page of an infinite-scroll list?

    easy
    1. AA scroll listener that calls getBoundingClientRect() on every event
    2. BPolling window.scrollY with setInterval
    3. CAn IntersectionObserver watching a sentinel element near the list end
    4. DLoading all pages up front and revealing them as the user scrolls
    Show answer

    Answer: C (An IntersectionObserver watching a sentinel element near the list end)

    IntersectionObserver reports visibility changes asynchronously, off the scroll hot path, so it avoids forced layouts on every scroll event. A rootMargin like 600px starts fetching before the user reaches the bottom. Also keep the footer reachable and offer a Load more fallback.

  15. 15.

    A feed now renders 10,000 items and scrolling is janky. What most directly helps?

    mid
    1. AWrap every item component in memo so items don't re-render
    2. BMove the feed data out of memory into IndexedDB
    3. CAnimate scrolling with CSS transforms instead of native scroll
    4. DVirtualize the list so only the visible items plus a small buffer exist in the DOM
    Show answer

    Answer: D (Virtualize the list so only the visible items plus a small buffer exist in the DOM)

    DOM size drives style, layout and memory costs, and virtualization keeps a few dozen nodes mounted regardless of list length (react-window, TanStack Virtual, Angular CDK virtual scroll). Trade-offs: variable heights must be measured, and browser find-in-page and screen readers only see mounted items. content-visibility: auto is a lighter alternative.

  16. 16.

    A dashboard shows live stock prices. Updates only flow from server to client, and you want automatic reconnection with minimal code over plain HTTP. What fits best?

    easy
    1. AWebSocket
    2. BServer-Sent Events (EventSource)
    3. CPolling the API every 100 ms
    4. DA WebRTC data channel
    Show answer

    Answer: B (Server-Sent Events (EventSource))

    SSE is a one-way stream over HTTP with reconnection built into EventSource, and it can resume using Last-Event-ID. WebSockets are the better choice when the client also sends frequent messages (chat, multiplayer), but you implement reconnection and heartbeats yourself.

  17. 17.

    A chat client sends a message, the socket drops, and the client retries after reconnecting. How do you avoid duplicate messages and keep ordering correct?

    hard
    1. AOnly resend when the user presses Send again after reconnecting
    2. BOrder messages by the timestamp from each sender's device clock
    3. CGive each message a client id for idempotent retries; order by a server sequence number
    4. DSwitch from WebSockets to HTTP polling, which never duplicates messages
    Show answer

    Answer: C (Give each message a client id for idempotent retries; order by a server sequence number)

    The server dedupes on the client id, so retrying is safe, and the client swaps its optimistic "sending" bubble for the confirmed message when the ack with that id arrives. Device clocks are skewed, so order should come from the server; sequence numbers also reveal gaps, which the client fetches after reconnecting.

  18. 18.

    After a server deploy, 50,000 chat clients disconnect at the same moment. Which reconnection strategy avoids a thundering herd?

    mid
    1. AExponential backoff with random jitter, capped at a maximum delay
    2. BReconnect immediately in a tight loop
    3. CReconnect every second on a fixed interval
    4. DWait for the user to reload the page
    Show answer

    Answer: A (Exponential backoff with random jitter, capped at a maximum delay)

    Exponential backoff spreads retries out while failures continue, and jitter desynchronizes clients so they don't all retry at the same instant. Also pause retries while the browser reports being offline and reconnect on the online event.

  19. 19.

    Which of these pieces of state belongs in the URL?

    easy
    1. AWhether a tooltip is open
    2. BThe auth access token
    3. CThe search query, filters and current page of a product list
    4. DThe value of a form input on every keystroke
    Show answer

    Answer: C (The search query, filters and current page of a product list)

    State in the URL is shareable, bookmarkable, and survives reloads and back/forward navigation, which is exactly what users expect for search and filters. Ephemeral UI state stays local, and secrets never go in URLs because they end up in history, logs and Referer headers.

  20. 20.

    An e-commerce site has 200,000 product pages whose prices change a few times a day. Pages must be fast and SEO-friendly, and a full static rebuild takes hours. Which rendering strategy fits best?

    mid
    1. AClient-side rendering, with the API returning JSON only
    2. BStatic generation of all 200,000 pages on every build
    3. CServer-side rendering on every request, with caching disabled
    4. DIncremental static regeneration: serve cached pages, regenerate in the background
    Show answer

    Answer: D (Incremental static regeneration: serve cached pages, regenerate in the background)

    ISR keeps the speed of static pages but regenerates each page after a revalidation window or when a webhook fires, so no full rebuild is needed; SSR behind a CDN with short cache lifetimes is a similar option. CSR hurts SEO and LCP, uncached SSR pays the rendering cost on every hit, and full SSG can't keep up with frequent changes across that many pages.

  21. 21.

    A page's main content renders quickly, but its recommendations section depends on a 2-second API call. What does streaming SSR with Suspense-style boundaries improve over classic SSR?

    hard
    1. ANothing: the HTML is still sent only once every section is complete
    2. BThe main content arrives first; the slow section streams in when its data is ready
    3. CIt removes the need to hydrate the page on the client
    4. DIt makes the 2-second API call itself return faster
    Show answer

    Answer: B (The main content arrives first; the slow section streams in when its data is ready)

    Classic SSR waits for all data before sending any HTML, so TTFB and FCP inherit the slowest dependency. Streaming flushes HTML progressively, with a fallback where the slow section will go, and frameworks can hydrate sections independently as they arrive.

  22. 22.

    What is the strongest reason to adopt micro-frontends?

    mid
    1. ATo improve runtime performance by loading smaller apps
    2. BTo make it easier to share state between features
    3. CTo let autonomous teams build and deploy parts of a large app independently
    4. DTo be able to mix several frameworks on one page
    Show answer

    Answer: C (To let autonomous teams build and deploy parts of a large app independently)

    Micro-frontends are an organizational scaling tool. They usually cost performance (duplicated dependencies, extra requests), consistency (design drift) and complexity (routing, shared state, versioning), so they pay off when team independence is the real bottleneck, not for a single small team.

  23. 23.

    Two micro-frontends loaded with Module Federation each bundle their own copy of React, and a shared component throws 'Invalid hook call'. What is the fix?

    hard
    1. APin both apps to the same React version, but keep bundling it separately
    2. BShare react and react-dom as singletons in the federation config
    3. CRender the shared component inside an iframe
    4. DRewrite the shared component without hooks
    Show answer

    Answer: B (Share react and react-dom as singletons in the federation config)

    Hooks break when a component is rendered by one copy of React but calls hooks from another. The shared config with singleton: true (and a compatible requiredVersion) makes everyone load one instance, which also avoids downloading React twice. The same applies to other libraries with module-level state, like routers and stores.

  24. 24.

    A news app's article API should show the latest content when online and the last cached version when offline. Which service worker caching strategy fits?

    mid
    1. ACache first
    2. BCache only
    3. CNetwork only
    4. DNetwork first, falling back to the cache
    Show answer

    Answer: D (Network first, falling back to the cache)

    Network-first tries the network (often with a timeout), updates the cache on success, and falls back to the cached response when offline. Cache-first suits versioned static assets and the app shell; stale-while-revalidate suits resources where slightly stale is fine, like avatars.

  25. 25.

    An offline-capable notes app needs to store thousands of structured notes, with attachments, on the device. Where should they go?

    easy
    1. AIndexedDB
    2. BlocalStorage
    3. CCookies
    4. DsessionStorage
    Show answer

    Answer: A (IndexedDB)

    IndexedDB is asynchronous, stores structured data and Blobs, supports indexes and transactions, and has much larger quotas. localStorage is synchronous (it blocks the main thread), stores only strings and is limited to a few megabytes; cookies are sent with every request.

  26. 26.

    How should an app produce messages like '1 file' / '5 files' in many languages?

    mid
    1. ATranslate both words and pick one with count === 1 ? t('file') : t('files')
    2. BAlways show 'file(s)' so one string works in every language
    3. CUse ICU plural messages or Intl.PluralRules; plural rules differ by language
    4. DConcatenate count + ' ' + t('file') and let translators adjust the word
    Show answer

    Answer: C (Use ICU plural messages or Intl.PluralRules; plural rules differ by language)

    Plural rules vary widely: Arabic has six categories, Polish distinguishes 'few' and 'many', and Japanese has a single form. An ICU message like {count, plural, one {# file} other {# files}} lets translators handle each locale, and avoiding concatenation keeps word order translatable.

  27. 27.

    You're adding Arabic (right-to-left) support. How should component CSS express spacing like 'margin between the icon and the label'?

    mid
    1. AUse logical properties like margin-inline-start, and set dir="rtl"
    2. BMaintain a second stylesheet with every left and right swapped
    3. CApply transform: scaleX(-1) to the body
    4. DPosition every icon absolutely
    Show answer

    Answer: A (Use logical properties like margin-inline-start, and set dir="rtl")

    Logical properties follow the writing direction, so one stylesheet works for both LTR and RTL once dir is set. Directional icons, such as back arrows, usually need mirroring too, while text itself should never be flipped with transforms.

  28. 28.

    You need to send session analytics when the user leaves the page, including on mobile. What is the most reliable approach?

    hard
    1. AA synchronous XHR inside an unload event handler
    2. BA normal fetch call inside a beforeunload handler
    3. CKeep it in localStorage and send it on the user's next visit
    4. Dnavigator.sendBeacon() when visibilitychange reports the page as hidden
    Show answer

    Answer: D (navigator.sendBeacon() when visibilitychange reports the page as hidden)

    On mobile, unload and beforeunload often don't fire because the page is backgrounded and then discarded, and unload listeners can also prevent the back/forward cache. The switch to hidden is the last event you can rely on, and sendBeacon (or fetch with keepalive: true) requests are allowed to outlive the page.

  29. 29.

    Production error reports show stack traces like a.js:1:48213. How do you make them readable without publishing your source code?

    mid
    1. ADisable minification in production builds
    2. BUpload source maps to the error tracker for each release, without serving them publicly
    3. CLog errors to the browser console instead of a tracker
    4. DWrap every function in try/catch to capture clearer messages
    Show answer

    Answer: B (Upload source maps to the error tracker for each release, without serving them publicly)

    The error tracker uses the uploaded maps, matched by release, to de-minify stack traces. Serving .map files publicly also works but exposes your source. Tagging errors with release, route and browser makes regressions after a deploy easy to spot.

  30. 30.

    Lighthouse scores your page 98, but users on low-end Android phones complain that it is slow. What should you rely on to understand real performance?

    easy
    1. ARun Lighthouse several more times and average the scores
    2. BRe-test on a faster laptop with a stable connection
    3. CField data from real users (RUM or CrUX), segmented by device, at the 75th percentile
    4. DNothing more: the Lighthouse score is the Core Web Vitals result
    Show answer

    Answer: C (Field data from real users (RUM or CrUX), segmented by device, at the 75th percentile)

    Lighthouse is a lab test on one simulated device and network, so it misses real devices, networks, caches and interactions (it can't measure INP at all). Core Web Vitals are assessed on field data at the 75th percentile. Collect RUM (for example with the web-vitals library) segmented by device class, and use lab tools to debug what it reveals.

  31. 32.

    A hero image is shown full-width on phones and at half width on desktops. How do you avoid sending a 2400px-wide file to phones?

    easy
    1. AUse srcset with width descriptors plus sizes, so the browser picks a file
    2. BScale it down with CSS width: 100% on small screens
    3. CLazy-load it so phones only fetch it when it's visible
    4. DConvert it to PNG, which compresses photos better
    Show answer

    Answer: A (Use srcset with width descriptors plus sizes, so the browser picks a file)

    With srcset="hero-800.jpg 800w, hero-1600.jpg 1600w, hero-2400.jpg 2400w" and sizes="(min-width: 1024px) 50vw, 100vw", the browser accounts for layout width and pixel density before downloading. Use picture for art direction or format fallbacks. CSS resizing still downloads the full file.

  32. 33.

    A component library is used by several apps that need runtime theming, including dark mode, without rebuilding the library. What is the best approach?

    mid
    1. AHard-code colors in each component and publish a separate build per theme
    2. BPass every color to every component as a prop
    3. CShip Sass variables that each app must recompile
    4. DExpose design tokens as CSS custom properties that components reference, so apps override the variables at runtime
    Show answer

    Answer: D (Expose design tokens as CSS custom properties that components reference, so apps override the variables at runtime)

    CSS variables cascade and can change at runtime, for example under a [data-theme="dark"] selector or a prefers-color-scheme media query, so one build supports any theme. Semantic token names like --color-surface keep themes consistent across components.

  33. 34.

    How do you stop your banking app from being loaded in an invisible iframe on an attacker's site (clickjacking)?

    mid
    1. AServe the whole app over HTTPS with HSTS
    2. BMark all session cookies HttpOnly and Secure
    3. CSend the CSP directive frame-ancestors 'none' (or X-Frame-Options: DENY)
    4. DAdd a CAPTCHA to every form and button
    Show answer

    Answer: C (Send the CSP directive frame-ancestors 'none' (or X-Frame-Options: DENY))

    frame-ancestors tells the browser which origins may embed the page: 'none' forbids framing entirely and 'self' allows only your own origin. X-Frame-Options is the older header with the same purpose. HTTPS and HttpOnly protect other things.

esc