# Use middleware in React Router

Used: react-router@7.3.0

If you're excited to use middleware in React Router, this guide will show you how to enable and implement them starting from version 7.3.0. You'll learn how to intercept requests and enhance loaders and actions on both the server and client.

## Enable Middleware in React Router

First, upgrade every React Router package to v7.3.0. The simplest way is to change in your `package.json` any `@react-router/*` package and the `react-router` package itself to that version.

Then go to your React Router config file and add this code.

```ts {% path="react-router.config.ts" %}
import type { Config } from "@react-router/dev/config";
import "react-router";

// This is not needed anymore if you use v7.6.0
declare module "react-router" {
  interface Future {
    unstable_middleware: true; // 👈 Enable middleware types
  }
}

export default {
  // ...Other options
  future: {
    unstable_middleware: true, // 👈 Enable middleware
    // ...Other future or unstable flags
  },
} satisfies Config;
```

The first thing is to enable `unstable_middleware` in the exported config object. This will enable middleware at runtime. The second thing is to add the `unstable_middleware` property to the `Future` interface in the `react-router` module. This will enable middleware types in your code.

### Breaking Change for Context

The types are important because middleware comes with a breaking change. Currently, a loader or action receives three arguments:

1. `request`
2. `params`
3. `context`

The `request` is a `Request` instance, `params` is an object with the route params like `:userId`, and `context` is an object with the interface `AppLoadContext`.

This `AppLoadContext` interface contains the values the HTTP server (e.g., Express, Hono, Cloudflare Workers, etc.) passes using `getLoadContext` to the React Router request handler.

When you enable middleware in your React Router application, this `AppLoadContext` is replaced with a new `unstable_RouterContextProvider` object. This is essentially a `Map` where middleware can store values that loaders or actions can read.

## Create a Middleware

Now that you have middleware enabled, you can create a custom middleware like this.

```ts {% path="app/middleware/session.ts" %}
import type {
  unstable_MiddlewareFunction,
  unstable_RouterContextProvider,
} from "react-router";
import { unstable_createContext } from "react-router";

const sessionContext = unstable_createContext<Session<Data, FlashData>>();

export const sessionMiddleware: unstable_MiddlewareFunction<Response> = async (
  { request, context },
  next
) => {
  let session = await sessionStorage.getSession(request.headers.get("Cookie"));

  context.set(sessionContext, session);

  let response = await next();

  response.headers.append(
    "Set-Cookie",
    await sessionStorage.commitSession(session)
  );

  return response;
};

export function getSession(context: unstable_RouterContextProvider) {
  return context.get(sessionContext);
}
```

This is a simplified implementation of a session middleware that uses React Router session storage to access the session and store it in the `unstable_RouterContextProvider` object.

Then we export a simple function to get the session from that context so we don't have to export the `sessionContext` object.

Finally, you can add the middleware to a route like this:

```tsx {% path="app/root.tsx" %}
import { sessionMiddleware } from "./middleware/session";
export const unstable_middleware = [sessionMiddleware];
```

And access the session in a loader or action like this:

```tsx {% path="app/routes/profile.tsx" %}
export async function loader({ context }: Route.LoaderArgs) {
  let user = getSession(context).get("user");
  if (!user) return redirect("/login");
  return { user };
}
```

And that's it! You can now use middleware in your React Router application.

## Typed Params in Middleware

So far, we have used only `request` and `context` in the session middleware. However, it also receives the `params`, like a loader or action. This is not typed because the middleware we created is generic.

If we want to create a middleware tied to a specific route, we can use the `Route.unstable_MiddlewareFunction` type, which will have the `params` typed.

```ts {% path="app/root.tsx" %}
import type { Route } from "./+types/root";

export const unstable_middleware: Route.unstable_MiddlewareFunction[] = [
  async ({ request, params, context }, next) => {
    // params is typed here
    return next();
  },
];
```

## Client-Side Middleware

React Router middleware is not only for server loaders and actions—you can also use them for client loaders and actions.

```tsx {% path="app/routes/profile.tsx" %}
export const unstable_clientMiddleware = [someClientMiddleware];
```

The `unstable_clientMiddleware` works like `unstable_middleware`, but for client loaders and actions. In this case, the type won't be `Route.unstable_MiddlewareFunction` but `Route.unstable_ClientMiddlewareFunction`.

The generic type is the same, `unstable_MiddlewareFunction`, but instead of `unstable_MiddlewareFunction<Response>`, you can just use `unstable_MiddlewareFunction`, since the `next` function in a client middleware doesn't return anything.
