TL;DR: TTFB measures server render path, not client assets, so start with the
x-vercel-cacheheader (HIT vs MISS) and acurl -wbreakdown before theorizing, then attack the four classic causes in order: per-request SSR, blocking data fetches, cold start / region mismatch, and middleware on the hot path, proving each fix with a measurement.
How to approach it
TTFB is time until the first byte of HTML, so client-side bundle size and images are off the table. This is server-side render path, by construction. Strong candidates segment the render path, name the rendering strategies (SSR/ISR/SSG/edge), and attach a measurement to every proposed fix, because the question explicitly asks you to prove it.
A strong answer
Measure before touching anything. Establish where the 3 seconds go. A curl -w timing breakdown separates DNS/TLS/connect from server think-time. Check whether it's all pages or some, all users or cold-cache only, p50 or tail. The x-vercel-cache header (HIT/MISS/STALE) tells you instantly whether responses are being served from the edge cache or rendered on every request, the single highest-yield check.
The four classic causes, in observed-frequency order:
- SSR on every request when the page doesn't need it. A page using
getServerSideProps(or dynamic rendering in the App Router viacookies(),headers(), orcache: 'no-store') renders per-request. If content changes hourly, that's waste. Fix: static generation with ISR (revalidate: 3600) so pages serve from the edge cache and regenerate in the background. Proof:x-vercel-cache: HITand TTFB dropping to tens of milliseconds. - Slow data fetches blocking the render. The render awaits a 2.5s backend/CMS/DB call. Fix: cache the fetch (
fetchrevalidation, Redis), parallelize sequential awaits, or stream. Send the shell immediately and<Suspense>the slow part so TTFB decouples from the slowest query. Proof: server timing logs around each fetch, before and after. - Cold starts and region mismatch. Serverless cold starts add hundreds of ms to seconds (worse with heavy dependencies). A function in us-east-1 calling a database in eu-west adds roughly 100ms per round trip, and ORMs that make several sequential queries multiply it: a page whose render runs six sequential queries (session, user, org, feature flags, content, related items, a completely ordinary ORM pattern) pays 6 x 100 = 600ms of pure geography before a single row is processed. The tell in the logs is distinctive and worth knowing cold: every query reports almost exactly the same latency, ~100ms, regardless of complexity, because the wire dominates the work. Locally the same queries run in 1-2ms and the app feels instant, which is why this bug ships. Fix: co-locate compute and data, batch or parallelize the queries, trim the bundle, consider edge runtime for thin pages. Proof: compare cold vs warm invocations, log per-query latency and watch the flat-100ms signature disappear.
- Middleware or auth on the hot path. Middleware running on every request doing a fetch to an auth service or feature-flag API. Fix: JWT verification locally instead of an introspection round trip, cache flag configs. Proof: middleware execution time in logs.
Sequence them: ISR/caching is usually the 10x win for content-like pages, data-layer fixes are the win for dynamic ones. State the decision rule: "Does this page need per-request data? If not, don't render it per request."
What interviewers probe next
- "The page is personalized, you can't just cache it." Split it: static shell served from edge, personalize client-side or stream the personalized fragment, or cache-by-segment with a small key (locale, plan tier) instead of per-user.
- "How do you keep it from regressing?" TTFB budget in CI/synthetic monitoring, alert on cache hit-ratio drops, dashboard real-user TTFB by region.
- "When does edge rendering actually help?" Thin, latency-sensitive pages without heavy Node dependencies and with data accessible from the edge. It does nothing if the bottleneck is a single-region database.
Key takeaways
- Check
x-vercel-cacheHIT vs MISS first; it decides the entire branch of your investigation. - The four causes in frequency order: per-request SSR, blocking fetch, cold start / region mismatch, middleware on the hot path.
- Every proposed fix carries its own proof metric, because the question asks you to prove it, not assert it.
Common mistakes
Talking about image optimization, bundle splitting, or lazy loading, all post-first-byte, and the fastest way to show you don't know what TTFB measures. Saying "add caching" without distinguishing SSG/ISR/SSR or knowing what makes a route dynamic. Proposing fixes with no verification step when the question literally asks for proof. And skipping measurement, picking a favorite fix before knowing whether the time is in cold start, data fetch, or render.
