Why Variables Cannot Be Used in Middleware Matcher

profile image

Let's explore the issues that occur when using variables in Next.js middleware matcher and their causes through analysis of Next.js source code.

This post has been translated by DeepL . Please let us know if there are any mistranslations!

Problem

An issue occurred where JavaScript was not executing and the screen was breaking on a specific page. Interestingly, this problem only appeared on the /signup page among the various paths defined in the middleware matcher.

Image.png

typescript
export const config = {
  matcher: [
    '/',
    '/account',
    Path.ITEMS, // Variable used here!
    '/blog/:path*',
    '/user/:path*',
    '/signin',
    '/signup',
    // ...
  ]
};

Cause

Explanation from Next.js Official Documentation

According to the Next.js official documentation, middleware matcher values must be statically analyzable at build time, and dynamic values like variables are ignored.

Initially, I thought there would be no problem because Path.ITEMS was declared as a const right above the config. However, issues still occurred, so I analyzed the Next.js source code to find the reason.

Next.js Config Analysis Process

Below is part of the actual Next.js code, showing the process used when analyzing SSG or middleware configurations:

typescript
export async function getPageStaticInfo(params: {
  nextConfig: Partial<NextConfig>
}): Promise<PageStaticInfo> {
  const fileContent = (await tryToReadFile(pageFilePath, !isDev)) || ''
  if (/runtime|getStaticProps|getServerSideProps|matcher/.test(fileContent)) {
    const swcAST = await parseModule(pageFilePath, fileContent)
    const config = tryToExtractExportedConstValue(swcAST, 'config') || {}
    // ...
  }
}

The important points in this code are:

  1. First, it reads the configuration file
  2. It looks for a variable named config
  3. It generates and parses an AST (Abstract Syntax Tree)

Looking more closely, Next.js only allows const declarations:

typescript
export function extractExportedConstValue(
  module: Module,
  exportedName: string
): any {
  for (const moduleItem of module.body) {
    if (!isExportDeclaration(moduleItem)) continue;

    const declaration = moduleItem.declaration
    if (!isVariableDeclaration(declaration)) continue;

    if (declaration.kind !== 'const') continue;
    // ...
  }
}

This code shows that values not declared with const are not extracted.

SWC's AST and Static Analysis

Next.js uses SWC (Speedy Web Compiler) to parse code and generate an AST. In this process, configurations using variables are difficult to analyze statically, making them hard to optimize at build time.

Example of a configuration that allows static analysis:

typescript
// ✅ Good example
export const config = {
  matcher: [
    '/',
    '/account',
    '/items', // Direct string usage
    '/blog/:path*',
  ]
};

Remaining Questions

I couldn't determine why other pages worked normally while only the /signup page had issues. This is likely related to peculiarities in Next.js's build process or code splitting.

Conclusion

Care must be taken when using variables in Next.js middleware matcher. Direct string literals should be used for build-time optimization and static analysis.

❤️ 0
🔥 0
😎 0
⭐️ 0
🆒 0