withastro/astro
Middleware
A user-defined function in src/middleware.ts that wraps every request before it reaches a page or endpoint. Astro composes user middleware with internal middleware (i18n, CSP) into a single chain.
Purpose
- Run code on every request (auth checks, request logging, header injection).
- Mutate
context.localsso pages and endpoints have shared per-request state. - Short-circuit a request to return a different
Response.
Key files
| File | Purpose |
|---|---|
packages/astro/src/core/middleware/index.ts |
Public exports: defineMiddleware, sequence. |
packages/astro/src/core/middleware/sequence.ts |
The sequence(...mws) combinator. |
packages/astro/src/core/middleware/callMiddleware.ts |
Runs the chain with a next function. |
packages/astro/src/core/middleware/defineMiddleware.ts |
The defineMiddleware typed-helper. |
packages/astro/src/core/middleware/noop-middleware.ts |
Used when no user middleware exists. |
packages/astro/src/core/middleware/vite-plugin.ts |
Emits the astro:middleware virtual module + the user-middleware loader. |
packages/astro/src/i18n/middleware.ts |
The framework-internal i18n middleware. |
Authoring
// src/middleware.ts
import { defineMiddleware, sequence } from 'astro:middleware';
const auth = defineMiddleware(async (context, next) => {
context.locals.user = await loadUser(context.cookies.get('session'));
return next();
});
const headers = defineMiddleware(async (context, next) => {
const response = await next();
response.headers.set('x-server-version', '1');
return response;
});
export const onRequest = sequence(auth, headers);onRequest is the convention; export const onRequest = ... is what the framework picks up.
Execution order
graph LR
A[Request] --> B[i18n middleware]
B --> C[User onRequest middleware]
C --> D[Internal CSP middleware]
D --> E[Render page or endpoint]
E --> F[Response]
F --> D
D --> C
C --> B
B --> G[Caller]Internal middleware (i18n, CSP) is inserted by the framework around user middleware. The order is enforced by core/middleware/sequence.ts and vite-plugin.ts.
Public API
astro:middleware exports:
defineMiddleware(fn)— typed wrapper.sequence(...fns)— compose multiple middleware.MiddlewareHandler,MiddlewareNexttypes.MiddlewareResponseHandlerfor response-only handlers.
The same names are also re-exported from astro/middleware for use in tooling.
Common mistakes
- Forgetting
await next()— your downstream middleware/page never runs. - Mutating
contextafternext()returns —context.localsis a regular object, not reactive; mutate before callingnext(). - Throwing from inside middleware — caught by
RenderContextand rendered as the configured 500 page (or the dev overlay in dev). UseAstroUserErrorfor user-facing problems.
Related pages
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.