Senior engineers are hired for decisions as much as for code: which library, whether to rewrite, when to say no. Interviewers probe this with "tell me about a technical decision you made and how it turned out" and "how would you evaluate X". Good answers show a process that produces defensible, documented, reversible decisions and communicates their costs honestly.
window at import, works in Nitro or at the edge); TypeScript quality; accessibility if UI; licence and supply-chain posture; community and documentation; exit cost (how hard is it to remove); a spike with a time box before committing.compatibilityVersion; REST → typed procedures by adding oRPC alongside; a monolith frontend → Nuxt by proxying routes. Rewrites lose the accumulated behaviour nobody documented; stranglers keep it.An ADR for a decision from this section:
# 7. Catalogue pages use swr (300 s) instead of prerendering or per-request SSR
Status: accepted (2026-09-21) · Supersedes: 3 (prerender whole catalogue)
## Context
50k products, prices change hourly, SEO required. Prerendering the catalogue takes 40 minutes per deploy and cannot follow price changes;
per-request SSR costs ~120 ms CPU per page and the origin saturates at peak. Personalised parts (cart badge, stock) are small.
## Options
1. Prerender everything on each deploy (current) — SEO fine, prices stale up to a day, slow deploys.
2. SSR per request — fresh, expensive, origin-bound.
3. swr 300 s via route rules, personalised parts client-side — fresh within 5 min, one render per URL per interval.
4. isr at the CDN — same as 3 with CDN regeneration; not supported by our current host.
## Decision
Option 3. `/c/**` and `/p/**` use `swr: 300` with cache keys including locale and currency; cart and stock load client-side;
checkout revalidates prices server-side. CMS and price webhooks clear affected keys.
## Consequences
+ Deploys no longer rebuild the catalogue; origin load drops to one render per URL per 5 minutes.
+ SEO unchanged (HTML served from cache with correct status).
− Prices may be up to 5 minutes stale on listing pages (mitigated at checkout).
− Cache storage must be shared (Redis) across instances; invalidation must be exercised in tests.
We will know it works by: origin CPU p95 under 40%, catalogue LCP p75 under 2.0 s, zero price-mismatch incidents at checkout.
A library evaluation checklist, as a scoring table:
Candidate: TanStack Query vs Pinia Colada vs built-in useAsyncData (for the dashboard app)
Criterion Weight TanStack Colada Built-in
Fit (SWR, mutations, 5 5 4 2
infinite, focus refetch)
SSR/Nuxt integration 4 4 5 5
Bundle size 3 3 4 5
Maintenance/bus factor 4 5 3 5
TypeScript quality 3 5 4 4
Exit cost 3 3 3 5
Weighted total 92 86 94 -> built-in for the marketing app; TanStack for the dashboard
A migration plan as a strangler, with measurable gates:
Vue 2 monolith -> Nuxt 4 (12 months, 6 engineers)
Phase 0 Safety net: E2E on the 8 critical flows; error tracking with releases; performance baselines.
Phase 1 Proxy: Nuxt in front, routeRules proxy everything to the old app; deploy; nothing changes for users.
Phase 2 Slice 1 (marketing pages): build in Nuxt, flip route rules per path; gate: LCP p75 ≤ old, error rate flat.
Phase 3 Shared kernel: design tokens + primitives as a layer; auth session bridge (shared cookie).
Phase 4 Slices 2..n by business value and coupling; each behind a flag with a rollback = route rule revert.
Phase 5 Remove the proxy and the old app; archive; ADR closing the migration with lessons.
Gates: every phase has a metric and a rollback; no phase longer than 6 weeks without a user-visible slice shipped.
Six months later nobody remembers why the cache is 300 seconds or why the account area is an SPA, and the team relitigates it in every planning meeting or, worse, changes it without knowing the consequence it prevented. A ten-line ADR costs less than one such meeting.
"We will rewrite it properly" discards behaviour nobody documented, freezes feature work for months, and ships a version one with fewer capabilities than the legacy app. Stranglers ship value from the first slice and keep the rollback trivial.
"By separating reversible from one-way decisions. Reversible ones, a UI library, a caching TTL, I make quickly with a time-boxed spike and record in a short ADR: context and the options considered, the decision, the consequences including what we are giving up, and how we will know it worked. One-way decisions, a database, a public API contract, a tenancy model, get a one-page RFC with a comment window and a named decider before the ADR. For libraries I score fit, maintenance signals, bundle size and SSR compatibility, TypeScript quality, accessibility, licence and exit cost. And I revisit records when consequences show up; changing a decision on evidence is part of the process, not a failure of it."
"As a strangler, never a rewrite. First the safety net: end-to-end tests on the critical flows, error tracking with releases, performance baselines. Then Nuxt goes in front of the old app and proxies everything, so deploying it changes nothing. Then slices by business value and low coupling, marketing pages first: build the slice in Nuxt, flip its route rules, gate on metrics, keep the rollback as a one-line revert. In parallel the shared kernel becomes a layer: tokens, primitives, an auth bridge sharing the session cookie. Every phase ships something visible within weeks; when the last slice moves, the proxy and the old app are removed and the ADR closes with the lessons. A rewrite would have frozen features for a year and lost the behaviour nobody wrote down."
Nothing yet. Notes filed here show up on this page and the section overview.
Worked designs
Four complete design-round answers in interview shape — an e-commerce catalogue and product page, a realtime analytics dashboard, a multi-tenant SaaS admin with a content site, and a file upload and processing pipeline — each with requirements, architecture, data and API, state placement, the hard part, cross-cutting concerns, trade-offs and what breaks at scale.
Tooling & delivery
The build and delivery toolchain a senior Nuxt engineer owns — Vite and Rolldown in Nuxt, linting, formatting and type checking as CI gates, package management and monorepos, CI/CD pipelines, and the developer-experience and debugging tools that make a team fast.