できない.dev

Next.js の middleware が実行されない

middleware.ts はプロジェクトルートに 1 ファイル限定で、matcher の設定と Edge runtime 制約に従う必要がある。
配置・matcher・export 名のどれかがずれると静かにスキップされる。

#nextjs#middleware#matcher#edge#routing

公開:

要約

middleware.ts が動かないときは「ファイルの場所」「matcher」「export 名」「Edge runtime 制約」を順に疑う。
公式の Middleware のとおり、middleware は プロジェクトルートに 1 ファイルしか置けず、複数置いても認識されない。

よくある原因

  1. 配置場所が間違っている: app/middleware.tspages/middleware.ts は無効。
    プロジェクトルート、または src/ を使う構成なら src/middleware.ts
  2. matcher が狭すぎる: matcher: "/api/:path*" だけだと通常ページで実行されない
  3. export 名のミス: myMiddleware のような任意名で export しても認識されない
  4. Edge runtime 非対応 API を使用: fs.readFileSync などを呼ぶと middleware ごと落ち、結果として実行されていないように見える

解決策

1. ルート配置を確認

my-app/
├── app/
├── src/                       # src ディレクトリを使う場合
│   ├── app/
│   └── middleware.ts          # ← ここ
├── middleware.ts              # ← または ここ(src を使わない場合)
└── next.config.js

app/middleware.ts ではない点に注意。

2. matcher を適切に書く

// middleware.ts
import { NextResponse } from "next/server";
import type { NextRequest } from "next/server";
 
export function middleware(req: NextRequest) {
  return NextResponse.next();
}
 
export const config = {
  matcher: [
    "/((?!api|_next/static|_next/image|favicon.ico).*)",
  ],
};

API ルートや静的アセットを除外しつつ全ページに効かせるテンプレ。
複数の matcher を配列で並べてもよい。

3. export 名は middleware

関数名は middleware 固定。

export function middleware(req: NextRequest) { /* ... */ }
// あるいは
export default function (req: NextRequest) { /* ... */ }

authmyMiddleware といった名前にすると、Next.js は middleware として扱わない。

4. Edge runtime で動く API のみ使う

middleware は Edge runtime で実行される。fs / child_process / Node.js 専用ストリーム等は使えない。
重い処理や DB アクセスは Route Handler 側で行い、middleware は認証ヘッダの検査やリダイレクト判定に限定する。

export function middleware(req: NextRequest) {
  const token = req.cookies.get("session")?.value;
  if (!token) {
    return NextResponse.redirect(new URL("/login", req.url));
  }
  return NextResponse.next();
}

dev サーバを再起動して console.log がターミナルに出れば動いている合図。

この記事は役立ちましたか?