Interview questions

Nuxt interview questions for senior developers (2026)

Senior Nuxt interview questions with model answers on useFetch and useAsyncData, hydration, state, route rules, middleware, Nitro server routes, configuration and the move from Nuxt 3 to Nuxt 4.

Here are 19 Nuxt interview questions with model answers, written for senior engineers who build with Nuxt 4 or maintain Nuxt 3 apps. They cover data fetching, hydration, state, rendering modes and route rules, middleware and plugins, Nitro server routes, runtime configuration, SEO, testing and the Nuxt 3 to Nuxt 4 upgrade. Core Vue topics such as reactivity, the Composition API and Pinia are on our Vue.js interview questions page. At Ryz, senior Vue and Nuxt engineers are sourced by recruiters, assessed in structured NTRVSTA AI interviews, and reviewed by recruiters before and after. The AI scores are one input. People make the decisions.

How to use these questions

Nuxt 4.0 was released in July 2025 and the 4.x line is current. Nuxt 3 still receives maintenance releases, so many teams run either a Nuxt 3 app, a Nuxt 3 app with compatibilityVersion: 4 turned on, or Nuxt 4. Nuxt 5, built on Nitro v3 and h3 v2, is in development, and from Nuxt 4.2 teams can test many of its changes with compatibilityVersion: 5. Tell the candidate which version you run, and accept answers in either vocabulary.

The strongest signal in a Nuxt interview is how a candidate thinks about the two runtimes: what runs on the server, what runs in the browser, what crosses between them in the payload, and when it runs twice by mistake. Ask them to trace a page load from request to hydrated page. Then have them build a page live.

Data fetching

When do you use useFetch, useAsyncData and $fetch?

useFetch(url) is the shortcut for calling an API in a page or component. useAsyncData(key, fn) wraps any async function, such as several calls, an SDK or a CMS client. Both run on the server during server rendering, store the result in the payload sent with the HTML, and reuse it during hydration instead of fetching again. $fetch is a plain HTTP client: use it in event handlers, actions after user input and server routes, not for initial data in setup.

What a strong answer shows: They explain the payload, and know that calling $fetch directly in setup fetches once on the server and again in the browser.

Write a page that loads a product and refetches when filters change.

<script setup lang="ts">
const route = useRoute();
const sort = ref<"price" | "rating">("price");

const { data: product, error } = await useFetch(
() => `/api/products/${route.params.id}`,
{ pick: ["id", "name", "price", "images"] }
);

const { data: reviews, status } = await useFetch("/api/reviews", {
query: { productId: computed(() => route.params.id), sort },
lazy: true,
default: () => []
});

if (error.value) {
throw createError({ statusCode: 404, statusMessage: "Product not found", fatal: true });
}
</script>

Reactive URLs and query values refetch automatically when they change. pick trims what goes into the payload, lazy lets the page render before the reviews arrive, and status drives the loading UI.

What a strong answer shows: They block rendering only on critical data, keep payloads small, and handle the not-found case with a real 404.

What are keys in useAsyncData, and what changed in Nuxt 4?

The key identifies the data in the payload and in Nuxt's cache. useFetch generates one from the URL and options, and useAsyncData takes one explicitly or generates one from the file and line. In Nuxt 4, every call with the same key shares the same data, error and status refs, so calls with one key must not use conflicting options such as different transform or pick. Keys can also be refs or getters, which refetch and store data separately when the key changes, and data is cleaned up when the last component using a key unmounts.

What a strong answer shows: They have debugged two components overwriting each other's data through a shared key and fixed it with distinct keys.

What other data-fetching defaults changed from Nuxt 3 to Nuxt 4?

data is a shallowRef, so mutating a nested property no longer triggers updates unless you pass deep: true. data and error default to undefined instead of null. pending is true only while status is "pending", so with immediate: false it starts as false. getCachedData now runs on every fetch, including refreshes triggered by watchers, and receives the cause of the request.

What a strong answer shows: They know null checks and nested mutations are the usual sources of upgrade bugs, and prefer replacing data over mutating it.

Rendering and hydration

What rendering modes does Nuxt support, and how do you mix them?

// nuxt.config.ts
export default defineNuxtConfig({
routeRules: {
"/": { prerender: true },
"/blog/**": { swr: 3600 },
"/products/**": { swr: 600 },
"/account/**": { ssr: false },
"/api/**": { cors: true, headers: { "cache-control": "no-store" } }
}
});

By default, Nuxt renders on the server for the first request and then runs as a single-page app. Route rules set rendering per path: prerender builds static HTML at build time, swr caches server-rendered responses and revalidates in the background, isr does the same with CDN caching on platforms that support it, and ssr: false renders in the browser only. Rules can also set headers, redirects and CORS.

What a strong answer shows: They choose a mode per route by how fresh and how personal the content is, and never cache personalized pages in a shared cache.

A page shows a hydration mismatch warning. What causes it, and how do you fix it?

The HTML from the server differs from what the browser renders during hydration. Common causes are dates and times formatted in different time zones, random values or IDs, reading window or localStorage during render, and invalid HTML nesting that the browser repairs. Fixes: format dates with an explicit time zone, use Vue's useId() for IDs, move browser-only reads into onMounted or wrap them in <ClientOnly>, and use useCookie for state both sides can read.

What a strong answer shows: They find the cause instead of hiding the component behind <ClientOnly>, which costs SEO and layout stability.

How do you reduce the JavaScript and hydration cost of a content-heavy page?

Use lazy components with the Lazy prefix so their code loads only when rendered. Since Nuxt 3.16, lazy components also accept delayed hydration props, such as hydrate-on-visible, hydrate-on-idle, hydrate-on-interaction and hydrate-never. Server components and islands render parts of the page on the server only, sending HTML without component JavaScript. Keep payloads small with pick and transform, and optimize images with @nuxt/image.

What a strong answer shows: They measure with nuxi analyze and Lighthouse before and after, and know which parts of the page actually need interactivity.

State, configuration and structure

Why is a ref declared at module scope dangerous in a Nuxt app?

On the server, modules are loaded once and shared across all requests. A ref at module scope therefore holds one user's data and leaks it into the next user's render. Use useState(key, init) for SSR-safe shared state, which is created per request and serialized into the payload, or Pinia through @pinia/nuxt for larger stores. Only put values that can be serialized into state that crosses to the browser.

What a strong answer shows: They recognize cross-request state pollution as a security bug, not only a correctness bug.

How does runtimeConfig work, and how is it different from app.config?

// nuxt.config.ts
export default defineNuxtConfig({
runtimeConfig: {
stripeSecretKey: "", // server only: NUXT_STRIPE_SECRET_KEY
public: {
apiBase: "/api" // exposed to the browser: NUXT_PUBLIC_API_BASE
}
}
});

Keys at the top level of runtimeConfig are available only on the server. Keys under public are sent to the browser. Both can be overridden at runtime by environment variables with the NUXT_ prefix, so one build can run in several environments. app.config.ts holds public settings fixed at build time, such as theme or feature labels, and can't be overridden by environment variables.

What a strong answer shows: They never put secrets under public, and know that only keys declared in the config can be overridden by environment variables.

What does the Nuxt 4 directory structure change?

Application code moves into app/ by default: pages, components, composables, layouts, middleware, plugins and app.vue. server/, public/, layers/ and modules/ stay at the project root, and a new shared/ folder holds code used by both the Vue app and the server, with auto-imports for shared/utils and shared/types. Nuxt also generates separate TypeScript projects for app, server, shared and build-time code, so server-only types don't leak into components.

What a strong answer shows: They know Nuxt detects the old layout and keeps it working, and they move folders in a separate commit from behavior changes.

What are Nuxt layers, and when do you use them?

A layer is a partial Nuxt app, with its own components, composables, pages, server routes and config, that another app extends through extends in nuxt.config.ts. Layers suit a shared design system and auth across several apps, or a base app that brands customize. Files in the extending app override files with the same path in the layer. Modules, by contrast, hook into the build with code and are better for integrations.

What a strong answer shows: They choose between layers, modules and a plain package by what needs to be shared: files and conventions, build behavior, or functions.

Routing, middleware and plugins

How do route middleware and server middleware differ?

Route middleware, in app/middleware, runs in the Vue app before navigating to a page: on the server for the first request and in the browser for later navigations. It can redirect with navigateTo or stop with abortNavigation, and a .global suffix runs it on every route. Server middleware, in server/middleware, runs in Nitro on every request to the server, including API calls, before any route handler.

What a strong answer shows: They know route middleware is for user experience, and that APIs must check authorization in server handlers, because anyone can call them directly.

How do you protect an authenticated area properly?

Add a named or global route middleware that redirects anonymous users to login, so the page experience is right. Then enforce access on the server: every API route under server/api reads the session from a cookie, validates it, and returns 401 or 403 itself. Mark private pages ssr: false or send cache-control: private so no shared cache stores them, and pass cookies through when server rendering calls your own API.

What a strong answer shows: Two layers, with the server as the real control. A candidate who relies on route middleware alone is a risk.

When do you write a Nuxt plugin, and what are the pitfalls?

Plugins run once when the app is created, which makes them right for registering Vue plugins, providing helpers with provide, and setting up clients such as analytics or a typed API client. Use the .client or .server suffix for one side only. Plugins run in order before the app renders, so slow async work in a plugin delays every page. Mark independent async plugins with parallel: true, and keep heavy setup out of them.

What a strong answer shows: They know plugin cost lands on every request, and they audit plugins when server response times grow.

Server routes and Nitro

Write a server API route with validation and errors.

// server/api/orders.post.ts
import { z } from "zod";

const Order = z.object({
sku: z.string().min(1),
quantity: z.number().int().min(1).max(100)
});

export default defineEventHandler(async (event) => {
const user = await requireUser(event);
const body = await readValidatedBody(event, Order.parse);
const order = await db.orders.create({ ...body, userId: user.id });
setResponseStatus(event, 201);
return { id: order.id, status: order.status };
});

Files under server/api become API routes, and the method suffix limits the route to POST. readValidatedBody throws a 400 with details when validation fails. createError raises other HTTP errors. Return only the fields the client needs.

What a strong answer shows: Auth inside the handler, schema validation on input, explicit status codes and a deliberately shaped response.

What is Nitro, and how does deployment work?

Nitro is Nuxt's server engine, built on h3. It builds the server routes and the rendering code into an output for a deployment preset: a Node.js server, serverless functions, or edge runtimes such as Cloudflare. It also provides storage and caching utilities, such as useStorage and defineCachedEventHandler, and scheduled tasks. Nuxt 5 is planned around Nitro v3 and h3 v2.

What a strong answer shows: They know edge presets limit Node.js APIs and database drivers, and pick a preset by what the server code needs.

Errors, SEO and testing

How does error handling work in Nuxt?

Throw createError with a status code. On the server, a fatal error renders the full-page error.vue with the right HTTP status. In the browser, showError shows the error page and clearError leaves it, optionally redirecting. <NuxtErrorBoundary> contains errors to one part of the page. Report errors from the app:error and vue:error hooks, or through a monitoring module, to your error tracker.

What a strong answer shows: They return real 404 and 500 status codes from server rendering instead of a 200 page that says "not found", which matters for SEO.

How do you handle SEO metadata in Nuxt?

Use useSeoMeta for typed title, description, Open Graph and Twitter tags, and useHead for links, scripts and other head tags. Both render on the server, so crawlers see them in the HTML. Set site-wide defaults in app.vue or nuxt.config.ts and per-page values from loaded data. Nuxt 4 uses Unhead v2. Add canonical URLs, a sitemap and structured data through modules or useHead.

What a strong answer shows: They make sure metadata comes from awaited data, not lazy data that arrives after the HTML is sent.

How do you test a Nuxt app?

Use @nuxt/test-utils with Vitest. Its Nuxt environment runs tests with auto-imports and plugins available, mountSuspended mounts components that use async setup and composables such as useFetch, and registerEndpoint mocks API routes. For end-to-end tests, build the app and drive it with Playwright, checking server-rendered HTML, status codes and hydration.

What a strong answer shows: Unit tests for composables, component tests with mocked endpoints, and a few end-to-end tests of critical flows against a production build.

Red flags to watch for

A practical exercise

Run a 90-minute pairing session on a prepared repo: a Nuxt 4 store with a product list, a product page, a cart and an account area. Seed it with problems: an account API route with no auth check, a module-scope ref holding the cart, a product page that calls $fetch in setup, a hydration mismatch from a formatted date, and a route rule that caches the account page. Ask the candidate to fix what matters most, explaining priorities as they go.

Hire senior Nuxt developers vetted with these questions

If you need engineers who already think this way, hire senior Vue.js and Nuxt developers through Ryz. They come from the top 1% of candidates we interview, work on your team and in your repos, and work on US business hours. Our vetting process shows how we evaluate them, and you can adapt our Vue.js developer job description for a Nuxt posting.

Related

FAQ

Should I interview for Nuxt 3 or Nuxt 4?

Interview for Nuxt 4, the current line, and accept answers in Nuxt 3 vocabulary. The core ideas are the same: server rendering, the payload, data fetching composables, route rules and Nitro. A candidate strong in Nuxt 3 can move to Nuxt 4 quickly, because most changes are the directory structure and data-fetching defaults.

Is Nuxt experience required, or is Vue experience enough?

Vue experience covers components, reactivity and state, but Nuxt adds server rendering, hydration, the payload and a server runtime. Ask one data-fetching question and one hydration question to see whether a Vue candidate adjusts quickly.

How many of these questions should a first round use?

Six to eight. Pick two on data fetching, one on rendering and hydration, one on state or configuration, one on middleware or server routes, and one on the Nuxt 4 upgrade if you are migrating. Then spend the remaining time on a short live exercise.

Questions we didn't answer? Email info@ryzlabs.com.

Explore Ryz Labs

Staff augmentationDedicated development teamsAI pod teamsForward deployed engineersNearshore software developmentAI engineering teamsHire engineers by roleRyz Labs vs competitorsAlternatives guidesBuyer guidesCase studiesHow we vet engineers
Ryz Labs

Senior engineers in your time zone. AI pod teams that ship.

Tell us who you need. You'll get a scoped plan, a price and the names of the people who would do the work.

Start a conversation →