Middleware (Experimental)

Middleware is enabled in Astro behind an experimental flag. Middleware allows you to intercept requests and responses and inject behaviors dynamically every time a page or endpoint is about to be rendered.

This also allows you to set and share request-specific information across endpoints and pages by mutating a locals object that is available in all Astro components and API endpoints

Middleware is available in both SSG and SSR Astro projects.

Enabling Middleware in your Project

Section titled Enabling Middleware in your Project

Enabling middleware should not cause any breaking changes in your project, but you may encounter errors or bugs as you use experimental middleware features.

Please refer to the middleware RFC for more information.

There are two ways to enable experimental middleware support: update astro.config.mjs manually or use the CLI.

To enable middleware manually, add the following lines to your astro.config.mjs configuration file:

import { defineConfig } from 'astro/config';

export default defineConfig({
  experimental: {
   middleware: true


To enable using the CLI instead, you can use the --experimental-middleware flag.

  1. Create src/middleware.js|ts (Alternatively, you can create src/middleware/index.js|ts.)

  2. Inside this file, export an onRequest() function. This must not be a default export.

export function onRequest ({ locals, request }, next) {
  // intercept response data from a request
  // optionally, transform the response by modifying `locals`
  locals.title = "New title"

  // return a Response or the result of calling `next()`
  return next()


  1. Inside any .astro file, access response data using Astro.locals
const data = Astro.locals;
<p>This {data.property} is from middleware.</p>


Example: redacting sensitive information

Section titled Example: redacting sensitive information

The example below uses middleware to replace “PRIVATE INFO” with the word “REDACTED” to allow you to render modified HTML on your page:

export const onRequest = async (context, next) => {
   const response = await next();
   const html = response.text();
   const redactedHtml = html.replace("PRIVATE INFO", "REDACTED");
   return new Response(redactedHtml, {
     status: 200,
     headers: response.headers


For more usage examples, please see the middleware RFC proposal

Multiple middlewares can be joined, in a specified order, using sequence():

import {sequence} from "astro/middleware";

function validation() {}
function auth() {}

export const onRequest = sequence(validation, auth);


import {sequence} from "astro/middleware";

async function validation(_, next) {
    console.log("validation request");
    const response = await next();
    console.log("validation response");
    return response;
async function auth(_, next) {
  console.log("auth request");
  const response = await next();
  console.log("auth response");
  return response;

async function greeting(_, next) {
  console.log("greeting request");
  const response = await next();
  console.log("greeting response");
  return response;


export const onRequest = sequence(validation, auth, greeting);


This will result in the following console order:

Terminal window
validation request
auth request
greeting request
greeting response
auth response
validation response


A required exported function from src/middleware.js that will be called before rendering every page or API route. It accepts two optional arguments: context and next(). onRequest() must return a Response: either directly, or by calling next().

An object that includes information to be made available to other middleware, API routes and .astro routes during the rendering process.

This is an optional argument passed to onRequest() that may contain the locals object as well as any additional properties to be shared during rendering. For example, the context object may include cookies used in authentication.

This is the same context object that is passed to API routes.

A function that intercepts (reads and modifies) the Response of a Request or calls the “next” middleware in the chain and returns a Response. For example, this function could modify the HTML body of a response.

This is an optional argument of onRequest(), and may provide the required Response returned by the middleware.

An object containing data from a Response that can be manipulated inside middleware.

This locals object is forwarded across the request handling process and is available as a property to APIContext and AstroGlobal. This allows data to be shared between middlewares, API routes, and .astro pages. This is useful for storing request-specific data, such as user data, across the rendering step.

locals is an object that lives and dies within a single Astro route; when your route page is rendered, locals won’t exist anymore and a new one will be created. Information that needs to persist across multiple page requests must be stored elsewhere.

A function that accepts middleware functions as arguments, and will execute them in the order in which they are passed.