Middleware - React router

December 20, 2025

Middleware in general

Middleware is a pattern that acts a layer between different parts of an application, processing requests and responses as they flow through the system.

Middleware typically has access to the request and response objects as long as the next function.

Each middleware can execute code, modify request/response objects, end the request-response cycle or call the next middleware.

Common use cases for middleware: Authentication, logging, error handling, CORS, validation and more.

Key advantage is you can use middleware, remove, or reorder them without modifying the core logic.

React router middleware

Middleware runs in a nested chain, executing from parent to child routes on the way "down" to your route handlers, then from your child routes back to parent routes on the way "up" after a response is generated.

TEXT

It's very important to understand when your middleware will run to make sure your application is behaving as you intended.

The steps needed to create a middleware in Framework mode:

1. Create a Context

Middleware uses a context provider instance to provide data down the middleware chain. You can create type-safe context objects using createContext

TSX
2. Export middleware from your routes
TSX
3. Update getLoadContext function

If you're using a custom server and a getLoadContext function, you will need to update your implementation to return an instance of RouterContextProvider, instead of a JavaScript object.

Server side middleware

Server middleware runs in the server in framework mode for HTML Document requests and .data requests for subsequent navigations and fetcher calls.

TSX

In a hydrated Framework Mode app, server middleware is designed in such that it prioritizes SPA behaviour and does not create a new network activity by default.

Client side middleware

Client middleware runs in the browser in framework mode and data mode for client-side navigations and fetcher calls. Client middleware differs from server middleware because there's no HTTP requests, so it doesn't have a response bubbling up.

TSX

Client middleware is simpler because since we are already on the client and are always making a "request" to the router when navigating. Client middleware will run on every client navigation, regardless of whether there are loaders to run.

Error handling in middleware

Middleware error handling follows the same principles as regular route loaders and actions. When an error occurs in middleware, it bubbles up the chain and can be caught by error boundaries.

TSX

Errors in middleware follow the normal React Router error flow they'll be caught by the nearest ErrorBoundary component, allowing you to display user-friendly error messages.

Middleware ordering and dependencies

The order of middleware in your export array matters because they execute sequentially. First middleware runs first, and each can modify the context or request before the next one.

TSX

Dependencies between middleware should be handled carefully. If one middleware depends on context set by another, ensure they're ordered correctly and handle missing context gracefully.

Performance considerations

Middleware adds execution overhead to every request, so keep it lightweight. Avoid expensive operations like heavy database queries or complex computations in middleware.

Good practices for performance:

Use caching for repeated operations, minimize I/O operations in middleware chains. Consider conditional middleware execution based on routes, profile middleware performance in production

TSX

Testing middleware

Middleware functions can be unit tested like any other async function. Mock the request, context, and next function to verify behavior.

TSX

Integration testing can verify the entire middleware chain works together with actual route loaders and components.

Conclusion

React Router middleware provides a powerful, composable way to handle cross-cutting concerns in your applications. By understanding the execution model, proper error handling, and performance implications, you can build robust middleware chains that enhance your application without compromising maintainability.