All jobs / Frontend / web developer
Performance interview questions
Performance questions a Frontend / web developer can be asked, from first job to senior. Open one to see the strongest answer and why it works.
Images pop the page down as they load. What do you set and why?
The strongest answer: Set width and height (or aspect-ratio) so the browser reserves space; keep max-width: 100% so they still shrink
Why it works: Reserved aspect ratio is the CLS fix. HTML width/height plus CSS is the usual pattern.
- Reserve space before the bytes arrive.
- Width/height or aspect-ratio on the image.
- Fluid CSS so it still fits small screens.
- Don't gate the whole page on images.
The main bundle includes an admin charts page most visitors never open. What do you do?
The strongest answer: Route-level import() / lazy for the admin page, and split heavy widgets — then look at the bundle graph
Why it works: Split on routes and expensive leaves. Measure so you don't guess.
- Split what users don't need yet.
- Lazy the admin route.
- Split heavy charts inside it if needed.
- Confirm with the bundle visualizer.
When would you render a marketing homepage on the server versus a settings screen on the client?
The strongest answer: SSR or SSG for public, SEO- and LCP-critical pages; client render (or islands) for authed chrome that is session-specific
Why it works: Match the render strategy to the page: public first paint vs private client state.
- Pick SSR/SSG vs CSR per page.
- Public marketing: server or static HTML.
- Authed settings: client is often enough.
- Don't treat 'we use React' as the strategy.
A late-loading banner pushes content down (CLS). How do you prevent it?
The strongest answer: Reserve space with min-height, aspect-ratio, or a skeleton — or overlay the banner; don't inject unsized blocks above content
Why it works: CLS cares about unexpected movement. Reserved space is the fix; a pretty animation is still a shift.
- Don't move painted content.
- Reserve the banner's box.
- Or overlay without pushing.
- Never silence the metric instead of fixing the shift.
LCP is a hero image. What do you change first?
The strongest answer: Prioritize it — fetchpriority high, real dimensions, a modern format, a CDN — and do not lazy-load the LCP image
Why it works: LCP wants the hero discovered early and lightweight. Lazy-loading it delays the metric on purpose.
- Help the hero, don't hide it.
- Discover it in the first HTML.
- Right size, modern format, high priority.
- Never lazy-load the LCP image.
Clicking Filter freezes the tab for about 400ms. How do you investigate?
The strongest answer: Use the Performance panel and React Profiler to find the long task — hydration, sync layout, or a heavy filter — then split, defer, or move work off the main thread
Why it works: Mid-level performance is a method: record, attribute, then change the work, not the chrome.
- Record the click.
- Find the long task in Performance / Profiler.
- Cut sync work: virtualize, defer, worker.
- Re-measure the same interaction.
Product asks if the new home is faster. What do you report?
The strongest answer: Field RUM — INP, LCP, CLS — by route, plus a lab trace for the regression; no single-reload vanity number
Why it works: Lab finds the bug; field tells you if users felt it. Percentiles and routes beat a screenshot score.
- Use field plus lab.
- Slice RUM by route and device.
- Reproduce the regression in a trace.
- Don't invent a percentage.
How do you ingest Web Vitals without drowning the backend or leaking PII?
The strongest answer: Sample or batch beacons, include route and device, keep them PII-free, and never block UX on the beacon
Why it works: RUM is a product: enough samples to see tails, no identity, no giant payloads.
- Measure the field cheaply.
- Batch or sample beacons.
- Slice by route, not by person.
- No PII, no full HTML.
How do you keep marketing JS from growing without anyone noticing?
The strongest answer: CI bundle budgets and a PR report (source-map explorer) — fail the build on unexpected growth
Why it works: Budgets only work when they gate the merge. Vite being fast to compile is not the same as a small graph.
- Put a number on the JS.
- Budget in CI.
- Show the delta on the PR.
- Fail unexpected growth, then decide.
Ten thousand rows in a div and the tab dies. What do you do?
The strongest answer: Window or virtualize the list (and recycle rows); don't mount ten thousand DOM nodes — paginate if the UX allows
Why it works: DOM count is the budget. Virtualization on web and FlashList / recycling on native are the same idea.
- Don't mount what you can't see.
- Virtualize or paginate.
- Recycle row components.
- Measure memory and INP after.
A feature flag flips the hero after hydrate (flicker). How do you prevent it?
The strongest answer: Evaluate the flag on the server or from a boot snapshot so the HTML matches; avoid client-only default-off then on
Why it works: Flicker is a hydration mismatch with extra steps. The first HTML must already know the variant.
- Flags that change HTML belong on the server.
- Read the flag before first paint.
- Hydrate the same tree.
- Don't default off and flip on.
An SSR page waits for user, then cart, then recommendations, sequentially. What's the issue and the fix?
The strongest answer: Parallelize independent server fetches, stream or defer the non-critical work, and avoid a second waterfall after hydrate
Why it works: Waterfalls are TTFB. Independent data should start together; recommendations can stream.
- Don't await what you can start together.
- Fire independent server fetches in parallel.
- Defer or stream extras.
- Don't re-fetch the same tree on hydrate.
A content site with a few interactive widgets — full CSR SPA or islands / edge?
The strongest answer: Islands or server components for mostly-static pages; a SPA for dense app chrome — decide with JS weight and TTFB, not habit
Why it works: Staff-level frontend is choosing the runtime per surface. Islands shine when HTML is the product.
- Match runtime to the page.
- Static + widgets: islands / RSC.
- App chrome: SPA is fine.
- Measure JS and TTFB; still test.
Personalized HTML at the edge versus cache hit ratio — how do you decide?
The strongest answer: Cache the shared shell, vary on explicit keys, and keep personal data in the client or short-lived fragments — never cache Set-Cookie HTML as public
Why it works: Edge helps when the key is honest. Personal HTML in a shared cache is a privacy incident.
- Cache what is shareable.
- Vary on explicit keys only.
- Personal bits stay private or uncached.
- Never store Set-Cookie HTML as public.
How does a frontend platform prove it is not making products slower?
The strongest answer: Shared RUM SLOs for INP and LCP per surface, budgets in CI, and regressions attributed to platform versus product
Why it works: Platform is accountable like any service: SLOs, owners, and blame that follows the commit, not the loudest team.
- Publish frontend SLOs.
- Watch INP/LCP per surface.
- Budget platform bytes in CI.
- Attribute regressions; don't hide tails.