Conrad Nuxt docs

The Nitro server

h3, unstorage and unenv, server routes and their types, validated input, event.$fetch, server middleware versus Nitro plugins and their hooks, response fragmentation with render:html and render:response, the three ways to cache, varies, and a reusable authenticated handler.

From the server, storage and caching parts of your Getting started III note, and the response fragmentation part of Getting started I.

Know

  • Nitro's parts: h3 (handlers, routing, request utilities), unstorage (useStorage() with drivers per environment), unenv (Node polyfills and stubs per preset).
  • Routes: server/api/ gets /api, server/routes/ doesn't; .get/.post suffixes; [id] and [...slug]; returned objects become JSON; useFetch is typed from them. shared/utils and shared/types are auto-imported on both sides.
  • Request utilities: getQuery, getRouterParam, readBody, getHeader, getCookie; validated versions getValidatedQuery, getValidatedRouterParams, readValidatedBody (400 on failure); errors with throw createError({ status, statusText }).
  • event.$fetch: an internal call that carries the incoming request's headers and context; plain $fetch on the server starts a fresh, anonymous request.
  • Middleware versus plugins: middleware runs per request and returns nothing (sets event.context); plugins run once at start-up and register hooks: request, beforeResponse, afterResponse, error, render:html, render:response, close.
  • Fragmentation: a Nitro plugin trims the head in render:html and turns the response into JSON { head, body } in render:response, so an old system can embed parts rendered by Nuxt.
  • Caching: route rules (by path, no code), defineCachedEventHandler (one handler, with getKey, varies, shouldBypassCache), defineCachedFunction (one expensive call, keyed by arguments). Request headers are dropped unless listed in varies. Memory per instance by default; mount Redis or KV to share.
  • server/utils: auto-imported across the server, the place for helpers like a defineAuthenticatedHandler wrapper.

Fact check of your notes

Gotcha· The h3 names: readBody, getValidatedRouterParams, createError

"await getBody(event)", "getValidatedRourerParam" and "use throwError() to throw": the functions are readBody(event), getValidatedRouterParams(event, validate) (plural) and throw createError({ status, statusText }). There's no getBody or throwError in h3.

Gotcha· The cache option is varies, and useStorage takes a mount name

"If I want to use any header, have to define that in the vary option": the option is varies. And "useStorage('provider')": the argument is the name of a mount point you configured under nitro.storage (or devStorage), like useStorage('redis'), not the driver or provider itself.

Gotcha· Middleware can return a value, it just shouldn't

"I can't return a value": you can, but whatever server middleware returns ends the request and is sent as the response, skipping the route handler. That's why middleware should only add to event.context or throw.

Exercise

Exercise
  • Write server/api/products/[id].get.ts with getValidatedRouterParams and Zod, call it with a bad id and read the 400, then check that useFetch('/api/products/1') is typed.
  • Add a Nitro plugin that logs the duration of every request with request and afterResponse; load a page and an API route and compare.
  • Wrap a handler in defineCachedEventHandler, read a custom header inside it, and see it missing until you add it to varies.
  • Build the fragment plugin from this page and request a page with ?fragment=1.

Be able to say

Be able to say· What's the difference between server middleware and a Nitro plugin?

"Middleware runs on every request before the handler and prepares the request, typically verifying the session and putting the user on event.context; it shouldn't return anything. A Nitro plugin runs once when the server starts and registers hooks for every request: afterResponse for timing, error for error tracking, render:html and render:response to change rendered pages."

Be able to say· How would you embed Nuxt-rendered parts into an old system's pages?

"With response fragmentation: the old system requests the fragment from Nuxt and inserts it. A Nitro plugin removes what the host page already has in render:html and turns the response into JSON with a head part and a body part in render:response. Asset URLs have to be absolute, CSS scoped, shared fragments cached, and the old system needs a timeout and fallback so Nuxt can't take it down."

Your notes

Open in Notes

Nothing yet. Notes filed here show up on this page and the section overview.