本文へ移動
verified onnext@16.3.5react@19
最終検証日 2026-09-26
Next.js道場

proxy(旧 middleware)の書き方と、名前が変わった理由

Next.js 16 では middleware という名前が非推奨になり、proxy という名前に変わりました。

検索して出てくる記事は、ほぼ全部が古い名前

「next.js middleware」で調べると、ほぼすべての記事が middleware.ts を書けと言います。Next.js 16 では、その名前は非推奨です。

実機で確かめました。middleware.ts のままビルドすると、こう出ます。

⚠ The "middleware" file convention is deprecated. Please use "proxy" instead.
  npx @next/codemod@canary middleware-to-proxy .

基本の形

proxy.ts はプロジェクトの根(app と同じ階層)に置き、proxy という名前の関数を書きます。よく使う3つの動きを1つにまとめた例です。

// proxy.ts
import { NextResponse, type NextRequest } from 'next/server'
 
export function proxy(request: NextRequest) {
  // URL はそのままで、別のページの中身を返す
  if (request.nextUrl.pathname.startsWith('/old-blog')) {
    return NextResponse.rewrite(new URL('/blog', request.url))
  }
  // Cookie が無ければ入口へ
  if (!request.cookies.has('session')) {
    return NextResponse.redirect(new URL('/login', request.url))
  }
  // そのまま通して、応答にヘッダーを足す
  const response = NextResponse.next()
  response.headers.set('x-from-proxy', 'yes')
  return response
}
 
export const config = {
  matcher: ['/dashboard/:path*', '/old-blog/:path*'],
}
この proxy.ts で開いたとき(実機で確かめた)
開いた URL結果
/dashboard(Cookie なし)307 で /login へ
/dashboard(Cookie あり)200。応答に x-from-proxy: yes
/old-blog/x200。URL はそのまま、中身は /blog
/about(matcher の外)proxy は動かない。ヘッダーも付かない

返すものは3種類です。NextResponse.next() で通す、redirect で別の URL へ移す、rewrite で URL を変えずに別の中身を返す。転送の状態コードの違いはredirect の使い分けにまとめています。

名前が変わっただけではない

なぜ変わったのかを知っておくと、使い方も迷わなくなります。

この仕組みは、要求が届いたあと、ページに渡る前に挟まるものです。できることは中心的に2つで、書き換えと行き先の変更です。

向いていること・向いていないこと
やりたいこと向いているか理由
ログインしていない人を入口へ飛ばすできる行き先を変えるだけ
言語や地域で出し分けるできる行き先を変えるだけ
ヘッダを足すできる書き換えるだけ
本人かどうかを厳密に判断するできないそこで完結させない
DB を見て中身を組み立てるできないページ側の仕事

「中間の処理」というより「前に立つ取り次ぎ」です。実態に名前を寄せたのが proxy という呼び名です。

書き換え

ファイル名と関数名が変わります。中身の考え方は同じです。

変わるのは名前。config はそのまま
middleware.ts(非推奨)
export function middleware() {
  return NextResponse.next()
}

ビルドのたびに告知が出る。

proxy.ts
export default function proxy() {
  return NextResponse.next()
}

告知は出ない。実機で確認ずみ。

公式の書き換えの道具が案内されます。手で作るより確実です。

npx @next/codemod@canary middleware-to-proxy .

掛ける範囲は matcher で狭める

export const config = { matcher: ['/about/:path*'] }

書き方はビルドの時点で固定の形に変換されます。実行時に組み立てるものではないので、変数や計算結果は入れられません。

形が違えばビルドで止まります。実機の文言です。

/proxy contains invalid middleware config: source must start with / at "matcher[0]"

先頭のスラッシュは補われません。何番目の指定かまで出るので、直す場所はすぐ分かります。

認可をここで完結させない

ログインが要る画面を守るとき、ここで飛ばすのは体験を良くするためであって、守るためではありません。

どこで何を判断するか
  1. Server
    proxy でおおまかに振り分ける

    Cookie が無ければ入口へ。速くて安い。

  2. Server
    ページやデータ取得で本人を確かめる

    ここが本当の守り。飛ばしそこねても、ここで止まる。

  3. Server
    Server Function でも同じ判断をする

    画面を通らずに直接呼ばれても、ここで止まる。

判断を1か所に集めたくなりますが、集めるなら手前ではなく奥です。手前は迂回され得ます。実際に動いているものが最小構成のログインにあります。

まとめ

  1. Next.js 16 で middleware は非推奨。proxy が正式な名前
  2. ビルドは通る。だから気づかないまま残る
  3. 両方置くとビルドが落ちる。残すのではなく履歴から戻す
  4. matcher はビルド時に固定。変数は入れられない。先頭のスラッシュは必須
  5. 認可をここで完結させない。守りは奥に置く

出典

このページの内容は上記の一次情報を基準に書いています。個人ブログや二次情報を根拠にしていません。

理解できたか試す

では、このコードはどうなりますか。

前から使っている middleware.ts をそのままにして Next.js 16 でビルドしました。どうなりますか。

この問題を解くこのテーマの問題 3 問