Middleware in Next.js allows you to execute code for every request, making it a powerful tool for handling authentication, logging, and more.
You can create a middleware function in Next.js by exporting a function from a file in the middleware directory.
Middleware functions can also be used to modify the request or response objects, such as adding a header or setting a cookie.
Setting Up Middleware
To set up middleware in Next.js, create a file named middleware.js in the root of your project or under the pages directory for page-specific middleware.
You can start with a basic structure that does nothing except forward the request. This is a good starting point for testing and experimenting with different middleware configurations.
Firstly, ensure you are working in a Next.js environment. If you've just set up your Next.js project, you need to create a new file named middleware.js at the root of your project or inside the pages directory for page-specific middleware.
Next.js supports API routes and middleware out of the box, but you may need to install additional libraries depending on your requirements. For instance, to handle cookies or sessions within your middleware.
To start working with middleware, you just need to create a single file `middleware.ts` (or .js) in the root of your project. You can start with sample code from documentation and check if it’s triggering with a single console.log.
Middleware Configuration
Middleware Configuration is crucial to ensure your Next.js middleware runs smoothly and efficiently. To begin, create a file named `middleware.js` in the root of your project or under the pages directory if you want to scope middleware to specific routes.
You can use environment variables to tailor your middleware according to the development, staging, and production environments by setting up a `.env.local` file in your project's root directory for development-specific configurations. This allows you to manage different middleware configurations for each environment.
To specify which routes the middleware logic should apply to, use the matcher configuration option to define targeted routes. This prevents unnecessary executions and reduces performance overhead. For example, you can use a route matcher like `/about` to apply middleware to the `/about` route.
Here's a list of examples for route matchers:
- /about: Matches the /about route.
- /blog/:slug: Matches any route that starts with /blog/ followed by a slug.
- /api/*: Matches any route that starts with /api/.
- /([a-zA-Z0-9-_]+): Matches any route that consists of alphanumeric characters, hyphens, and underscores.
Cors
Cors middleware is a crucial component in Next.js applications, allowing for cross-origin resource sharing.
This middleware function adds CORS headers to the response to allow requests from any origin, methods, and headers.
For preflighted requests (OPTIONS method), it responds immediately with appropriate headers and a status code of 200.
To implement CORS middleware, you can use a custom middleware function that adds the necessary headers to the response.
Here's a basic example of how you can create a CORS middleware function:
By adding this middleware function to your Next.js application, you can enable CORS and allow requests from any origin.
Configuring for Different Environments
Configuring for Different Environments is crucial when working with middleware. You can tailor your middleware to adapt to different environments using environment variables in your Next.js project.
Set up a .env.local file in your project's root directory for development-specific configurations. This will allow you to manage different settings for your development environment.
To adapt to different environments, use conditional logic in your middleware or configuration. This will enable your middleware to behave differently depending on the environment.
Here's a breakdown of the different environments and how to configure them:
Remember to use the correct environment file for each environment to ensure your middleware is configured correctly.
Matcher Config
Middleware in Next.js can be configured to run on specific routes, and this is where the matcher config comes in. The matcher config is used to define which routes the middleware logic should apply to.
A recommended matcher config is to enable a redirect at the root route (/) to a suitable locale, and to internationalize all pathnames starting with a locale (e.g. /en/about). This can be achieved by using a static matcher config.
Here's an example of a matcher config that enables a redirect at the root route to a suitable locale:
```javascript
matcher: {
'/': {
redirect: {
destination: '/en',
permanent: false,
},
},
}
```
This config tells Next.js to redirect any requests to the root route (/) to the /en route.
Alternatively, you can implement a programmatic condition in the middleware to achieve the same result. For example:
```javascript
const middleware = (req, res, next) => {
if (req.url === '/') {
res.redirect('/en');
} else {
next();
}
};
```
This middleware function checks if the request URL is the root route (/), and if so, redirects the request to the /en route.
You can also use regular expressions to match routes in the matcher config. For example:
```javascript
matcher: {
'/:locale': {
// middleware logic here
},
}
```
This matcher config will apply the middleware logic to any route that starts with a locale (e.g. /en/about, /fr/about).
In summary, the matcher config is a powerful tool in Next.js middleware that allows you to define which routes the middleware logic should apply to. By using a static matcher config or implementing a programmatic condition, you can ensure that your middleware logic is only applied to the routes that need it.
Logging and Analytics
Logging and analytics are crucial aspects of middleware configuration. Middleware allows you to log requests, responses, or other information related to the application.
You can use middleware to log information such as request headers, response status codes, and more. This includes logging the accessed path and user agent for each request, as seen in some implementations.
Middleware can be used to integrate with third-party monitoring or analytics tools seamlessly. This enables easy filtering of data, monitoring of user interactions, and the extraction of insights for performance optimization and anomaly detection.
Here are some examples of what you can log using middleware:
- Request headers
- Response status codes
- Accessed path
- User agent
Logging and analytics with middleware can help you track request patterns, performance metrics, or unusual activities. This aids in both performance tuning and security monitoring.
Request and Response Handling
You can intercept requests to add a simple logging mechanism in Next.js middleware. This can be particularly useful for monitoring or debugging purposes.
Middleware in Next.js operates at the network edge, offering capabilities to modify incoming requests. The NextResponse API empowers you to redirect incoming requests to an alternate URL, revise responses by showcasing a specified URL, and configure request headers for API Routes.
You can directly responding from Middleware by returning either a Response or NextResponse instance, which has been available since Next.js version 13.1.0.
The NextResponse object is central to what you can do within your middleware. You can respond to requests, modify the response, and rewrite the request path.
You can use conditional statements in your middleware functions to perform different actions based on specific conditions. This is handy when you want to serve the content of one path in response to another request path without an outright redirection.
Here are some key features of the NextResponse API:
- Redirect incoming requests to an alternate URL.
- Revise responses by showcasing a specified URL.
- Configure request headers for API Routes, getServerSideProps, and rewrite destinations.
- Implement response cookies.
- Define response headers.
Middleware can also be used to log requests, responses, or other information related to the application. You can use middleware to log information such as request headers, response status codes, and more.
Middleware should include robust error handling to manage unexpected scenarios like token validation failures. Ensure that your middleware returns appropriate responses, redirects, or error messages to guide users through such cases, preventing any interruptions in the application’s flow.
Routing and Path Matching
Routing and Path Matching is a crucial aspect of Next.js Middleware. Middleware will be invoked for every route in your project.
To prevent unnecessary executions, you can specify a matcher to define the routes that the middleware should apply to. This can be a string or a regular expression that matches the route pattern.
Here are some examples of matchers: /about: Matches the /about route./blog/:slug: Matches any route that starts with /blog/ followed by a slug./api/*: Matches any route that starts with /api/./([a-zA-Z0-9-_]+): Matches any route that consists of alphanumeric characters, hyphens, and underscores.
You can also specify multiple matchers by using an array of strings or regular expressions, which will invoke the middleware for any route that matches any of the specified matchers.
Matching Paths
Matching paths is a crucial aspect of routing and path matching. You can specify a matcher to define the routes that the middleware should apply to, which can be a string or a regular expression that matches the route pattern.
A matcher can be as simple as "/about" to match the /about route, or as complex as "/blog/:slug" to match any route that starts with /blog/ followed by a slug.
You can also specify multiple matchers by using an array of strings or regular expressions. Middleware will be invoked for any route that matches any of the specified matchers.
Here are some examples of matchers:
- /about: Matches the /about route.
- /blog/:slug: Matches any route that starts with /blog/ followed by a slug.
- /api/*: Matches any route that starts with /api/.
- /([a-zA-Z0-9-_]+): Matches any route that consists of alphanumeric characters, hyphens, and underscores.
Matching multiple paths can be achieved by using an array of strings or regular expressions, allowing you to specify multiple routes for the middleware to apply to.
Domain-Based Routing
Domain-based routing allows your app to automatically detect the user's preferred language and redirect them to the correct domain if necessary. This is achieved by matching the request against the available domains and determining the best-matching locale.
The locale is detected based on four priorities, which are:
- A locale prefix is present in the pathname (e.g. ca.example.com/fr)
- A locale is stored in a cookie and is supported on the domain
- A locale that the domain supports is matched based on the accept-language header
- As a fallback, the defaultLocale of the domain is used
If a domain receives a request for a locale that is not supported, the middleware will redirect the user to an alternative domain that does support the locale.
The best-matching domain is detected based on four priorities:
- Stay on the current domain if the locale is supported here
- Use an alternative domain where the locale is configured as the defaultLocale
- Use an alternative domain where the available locales are restricted and the locale is supported
- Use an alternative domain that supports all locales
Initial Authentication and Authorization
Initial authentication and authorization are crucial for protecting sensitive routes in your app. Middleware serves as an ideal gatekeeper for initial authorization checks.
Verifying a valid token or checking for an authentication cookie ensures that only authorized users can reach sensitive routes. This streamlines the access control process without adding client-side complexity.
To integrate authentication, you can combine middleware from different services, like Supabase and next-intl. By adapting the middleware utils, you can create a seamless experience for users.
Unauthorized visitors can be redirected to a login page or shown a custom error message. This approach helps maintain a smooth user experience while ensuring security.
Frequently Asked Questions
Where to put the middleware file in NextJS?
Place the middleware file (middleware.ts or .js) in the root of your project, alongside files like pages or app, or inside the src directory if applicable
How to create middleware in NextJS 14?
To create middleware in NextJS 14, create endpoints in the API folder and utilize the IPI folder to catch requests. This setup enables you to implement middleware functionality effectively.
Sources
- https://loadforge.com/guides/nextjs-middleware-key-to-faster-web-applications
- https://www.geeksforgeeks.org/middlewares-in-next-js/
- https://next-intl-docs.vercel.app/docs/routing/middleware
- https://pagepro.co/blog/next-js-middleware-what-is-it-and-when-to-use-it/
- https://codeparrot.ai/blogs/nextjs-middleware-simple-guide-to-control-requests
Featured Images: pexels.com