Middleware
Handlers answer one route. +middleware.* files wrap every route at
their level and below — the request pipeline’s layers. A middleware
default-exports a handler (built with Run.ALL to run for every
method, or a verb helper to filter), receives the same context, and
calls next() to pass control inward:
export default Run.ALL(async (context, next) => { const started = Date.now(); const response = await next(); // everything inside runs here console.log(`${context.method} ${context.url.pathname} — ${Date.now() - started}ms`); return response;});The execution order is an onion — marko-run’s own diagram, in text:
root middleware → nested middleware → handler → layouts+page render response streams back out through each, in reverseCode before next() runs on the way in; code after runs on the way
out, response in hand — timing, logging, auth checks, header stamping
all fall out of that shape. Middleware also joins the two systems you
know: it can pass data (next({ user }) merges into $global.data)
and declare shared validation options for everything below.
The site on the right has a root middleware stub and an admin/
section with its own:
- Complete the root middleware with the timer above.
- Complete
admin/+middleware.js: beforenext(), checkcontext.url.searchParams.get("key") === "letmein"— if not,return new Response("Forbidden", { status: 403 }). - Open the terminal tab and watch:
/logs one line;/adminwithout the key is rejected before the handler ever runs;/admin?key=letmeinpasses and logs from both layers in onion order.
- Installing dependencies
- Starting dev server