Performance

Performance

Where the time actually goes in a Nuxt app, the senior answer shape, and why a layer author's first performance question is what the layer costs every consuming app.

Performance questions in an interview are rarely about knowing a trick. They are about whether you can locate a problem before reaching for a fix. Every answer in this section follows the same shape: measure → name the layer → apply the matching lever → verify with the same measurement. A candidate who opens with "I would add caching" has skipped the only part that matters.

Know

  • Five places the time goes, in the order you should walk them:
    1. Build and dev time — module setup, Vite pre-bundling, template generation, HMR. Your home turf as a tooling author, and the cost your teammates feel every day.
    2. Server time (TTFB) — awaited data in setup, rendering, payload serialisation, cache hits and misses.
    3. Network — HTML plus inline payload size, JS chunks, images, fonts, third-party scripts.
    4. Client — parse and compile, hydration cost, LCP, INP, CLS.
    5. Cost and scale — SSR CPU per request, cache hit ratio, edge versus origin.
  • Each layer has its own instrument. hyperfine and nuxt analyze for build; curl -w timings, autocannon and --cpu-prof for server; the Network panel and the DevTools payload tab for the wire; Lighthouse, web-vitals and the Performance panel for the client. Naming the instrument is half the answer.
  • A layer or module is a tax on every consumer. Global components land in the entry chunk; every plugin runs on every SSR request and every page load; CSS and fonts ship to everyone; a heavy dependency enters twenty bundles. The first question about a shared package is not "is it fast?" but "what does it cost an app that installs it and uses nothing?"
  • Budgets beat vigilance. A bundle-size check and a build-time check in CI catch the regression that a code review will not.

The answer shape, worked

"TTFB went from 180 ms to 900 ms after the last release."

A senior answer: measure first with curl -s -o /dev/null -w '%{time_starttransfer}\n' against a warm server to confirm it is the server and not the network; profile one request with node --cpu-prof .output/server/index.mjs under autocannon to see whether the time is in data fetching, rendering or serialisation; if it is data, look for sequential await useAsyncData calls in setup and for a cache that stopped hitting; apply the matching lever (parallelise, lazy: true for non-critical data, or a route rule); re-measure the same way and quote the delta.

The wrong answer names a lever first ("I'd add SWR"), because SWR on a personalised route is also a security incident, and caching a slow query hides it until the cache is cold.

Gotcha· Measuring in dev

Dev mode is unbundled, uncached and instrumented. Every number that matters comes from nuxt build plus node .output/server/index.mjs (or a preview deployment), with the server warmed up first. The only thing worth measuring in dev is dev itself: startup and HMR.

Exercise

Exercise
  • Build the playground, start the built server, and record four numbers in your notes: cold build time (hyperfine), TTFB on a warm server (curl -w), client entry chunk size (du -sh .output/public/_nuxt), and Lighthouse LCP. These four are your baseline for every exercise in this section.
  • Add your layer or module to the app and record the same four numbers again. The deltas are the story you tell in the interview.

Be able to say

Be able to say· How do you approach a performance problem?

"I measure before I touch anything, and I name the layer the time is in: build, server, network or client. Each has its own instrument, so the measurement tells me which lever is even relevant. Then I apply the matching lever and re-measure the same way, so I can quote a delta rather than a feeling. For shared tooling I also measure what the package costs an app that installs it and uses nothing, because that cost is multiplied by every consumer, and I put that number in CI as a budget."