I'm trying to use a centralized NAV_LINKS constant to define my protected routes for a Next.js middleware. The goal is to avoid repeating the route paths in both my component and the middleware config.matcher.
I have a constants.ts file with a nested object defining my navigation links, like this:
// constants.ts
export const NAV_LINKS = {
navMain: [
{
title: "Getting Started",
items: [
{ title: "dashboard", url: "/dashboard" },
{ title: "Users", url: "/users" },
],
},
],
};
In my middleware.ts, I'm trying to dynamically generate the matcher array by importing this constant and using a function to extract the URLs.
// middleware.ts
import { NAV_LINKS } from "./constants";
const getProtectedRoutes = (links: typeof NAV_LINKS) => {
return links.navMain.flatMap((section) =>
section.items.map((item) => item.url)
);
};
const protectedRoutes = getProtectedRoutes(NAV_LINKS);
export const config = {
matcher: [
...protectedRoutes.map((path) => `${path}/:path*`),
"/login",
],
};
This setup works perfectly in my application's logic (e.g., when I log protectedRoutes, the array is correct). However, when I run the application, the middleware does not seem to run on the routes defined in NAV_LINKS, or it causes an ERR_TOO_MANY_REDIRECTS error.
If I replace the dynamic array with a static, hard-coded array, it works as expected.
// This works
export const config = {
matcher: ["/dashboard/:path*", "/users/:path*", "/login"],
};
Why does the matcher fail to work with a dynamically generated array from a constant? Is there a limitation in Next.js's middleware configuration?