メインコンテンツへスキップ
友田 陽大
Vercel 本番運用
Vercel
Next.js
セキュリティ
パフォーマンス
TypeScript
フロントエンド
アーキテクチャ設計

Vercel Routing Middleware 実装ガイド:認証ゲート・パーソナライズ・A/B・リダイレクトをキャッシュ前で

Vercel公式に忠実なRouting Middleware実装ガイド。リクエスト処理前・キャッシュ前にグローバル実行されるミドルウェアで、認証ゲート・地域/デバイス別パーソナライズ・A/Bテスト・緊急リダイレクト・IPブロックを実装。Edge/Node.js/Bunランタイムの選択、Edge Configとの組み合わせ、14KB URL・4MB body等の制限、observabilityまで実コードで解説します。

公開日
読了時間
7分
著者
友田 陽大
シェア

「ログインしていないユーザーを /dashboard から弾きたい」「国ごとに通貨表示を変えたい」「新デザインを5%のユーザーにだけ出したい」——これらをページの手前で、しかも静的キャッシュを活かしたまま実現するのが Routing Middleware です。

この記事は Vercel Routing Middleware の公式仕様に忠実に、認証ゲート・パーソナライズ・A/B・リダイレクトの実装をまとめます。全体像は Vercel 本番運用ガイド を参照してください。


Routing Middleware とは

公式の定義はシンプルです。

Routing Middleware executes code before a request is processed on a site, and are built on top of fluid compute.(— Routing Middleware

重要な性質:

  • リクエスト処理の前・CDN キャッシュの前にグローバル実行される。だから静的生成コンテンツにパーソナライズを足せる(キャッシュは効かせたまま、出し分けだけ手前で)。
  • Fluid Compute 上で動くFunctions)。
  • フレームワーク非依存——middleware.ts をプロジェクトルートに置けば、どのフレームワークでも動く。Next.js の middleware と同じファイル名だが、Vercel プロダクトとしてはフレームワークを問わない
// middleware.ts(プロジェクトルート)
export default function middleware(request: Request) {
  const url = new URL(request.url);

  // 旧パスをリダイレクト
  if (url.pathname === "/old-page") {
    return new Response(null, {
      status: 302,
      headers: { Location: "/new-page" },
    });
  }

  // 次のハンドラへ続行
  return new Response("Hello from your Middleware!");
}

ランタイムを選ぶ(Edge / Node.js / Bun)

既定は Edge ランタイム。フル Node.js API が要るなら confignodejs に切り替えます。

// middleware.ts — Node.js ランタイムに切り替え
export const config = {
  runtime: "nodejs", // 既定は 'edge'
};

export default function middleware(request: Request) {
  return new Response("Hello from Node.js Middleware!");
}
ランタイム使いどころ注意
Edge(既定)軽量・極小レイテンシのリダイレクト/ヘッダ操作env は 1変数 5KB まで
Node.jsフル Node.js API・既存ライブラリが必要Fluid Compute 上で動き、Functions 課金が発生
BunBun ネイティブvercel.jsonbunVersion + runtime nodejs

Next.js で Node.js ミドルウェアを使う場合は、next.config.tsexperimental.nodeMiddleware: true を有効化し、middleware.tsconfig.runtimenodejs にします(matcher も併用可)。


ユースケース①:認証ゲート

未認証ユーザーを保護ルートからログインへ。ページの手前で弾くので、保護ページのレンダリングコストもかかりません。

// middleware.ts
const PROTECTED = ["/dashboard", "/settings", "/billing"];

export default function middleware(request: Request) {
  const url = new URL(request.url);
  const needsAuth = PROTECTED.some((p) => url.pathname.startsWith(p));
  if (!needsAuth) return; // 続行

  const session = request.headers.get("cookie")?.includes("session=");
  if (!session) {
    const login = new URL("/login", request.url);
    login.searchParams.set("next", url.pathname); // 戻り先を保持
    return Response.redirect(login, 307);
  }
}

重要(信頼境界):ミドルウェアでの認証チェックは「UX の最適化」であって、最終的な認可ではありません。Cookie の存在チェックだけで認可を確定しない——ページ/APIのサーバー側でトークンを必ず検証します。中間者やリプレイを考えれば、認可はサーバー/DBで強制するのが鉄則です。Cookie の改ざん対策には署名付き Cookie を。


ユースケース②:パーソナライズ(地域・デバイス・言語)

静的ページをキャッシュしたまま、国・言語・デバイスで出し分けます。Vercel は地理情報ヘッダ(x-vercel-ip-country 等)を提供します。

// middleware.ts — 国に応じてロケールへ rewrite(キャッシュは活きる)
export default function middleware(request: Request) {
  const url = new URL(request.url);
  if (url.pathname !== "/") return;

  const country = request.headers.get("x-vercel-ip-country") ?? "US";
  const locale = country === "JP" ? "ja" : "en";

  // rewrite(URLは変えずに内部的に別ページを返す)
  const rewritten = new URL(`/${locale}`, request.url);
  return new Response(null, {
    status: 200,
    headers: { "x-middleware-rewrite": rewritten.toString() },
  });
}

キャッシュキーに属性を含めたい場合は、レスポンス側で Vary を使います(キャッシュ戦略)。


ユースケース③:A/B テストのバケット割り当て

新デザインを一部ユーザーに。Cookie でバケットを固定し、同一ユーザーには一貫した体験を返します。

// middleware.ts
export default function middleware(request: Request) {
  const url = new URL(request.url);
  if (url.pathname !== "/") return;

  const cookie = request.headers.get("cookie") ?? "";
  let bucket = cookie.match(/ab=(a|b)/)?.[1];

  const res = new Response(null, { status: 200 });
  if (!bucket) {
    bucket = Math.random() < 0.5 ? "a" : "b";
    res.headers.append("set-cookie", `ab=${bucket}; Path=/; Max-Age=2592000`);
  }
  res.headers.set(
    "x-middleware-rewrite",
    new URL(bucket === "b" ? "/home-variant" : "/", request.url).toString(),
  );
  return res;
}

段階的な本番ロールアウトそのものは、ミドルウェアの自作 A/B より Rolling Releases の方が安全(Skew Protection・メトリクス比較・即ロールバック付き)。ミドルウェア A/B は「機能フラグ的な恒常的な出し分け」に向きます。


ユースケース④:緊急リダイレクト・IP ブロック(Edge Config 連携)

ミドルウェアで DB を叩くとレイテンシが乗ります。フラグ・リダイレクト表・IP ブロックリストは Edge Config(P99 15ms 未満)に置くのが定石です。

// middleware.ts — Edge Config で「再デプロイなしの」制御
import { get } from "@vercel/edge-config";

export default async function middleware(request: Request) {
  // メンテモード(コードを触らず即ON/OFF)
  if (await get<boolean>("maintenance_mode")) {
    return Response.redirect(new URL("/maintenance", request.url), 307);
  }

  // 悪性IPブロック(アップストリームを呼ばずに弾く)
  const ip = request.headers.get("x-forwarded-for")?.split(",")[0];
  const blocked = (await get<string[]>("blocked_ips")) ?? [];
  if (ip && blocked.includes(ip)) {
    return new Response("Forbidden", { status: 403 });
  }
}

大規模な IP ブロック・レート制限・bot 対策は、ミドルウェアよりも Vercel WAF / BotID(入口で関数を呼ぶ前に効く)が適切。ミドルウェアは「アプリ寄りのロジック」、WAF は「プラットフォーム入口」と役割分担します。


制限とコスト

項目制限
URL 最大長14 KB
リクエスト本文4 MB
リクエストヘッダ数64
リクエストヘッダ長16 KB
Edge env 変数1変数 5KB
  • コストは Fluid Compute モデル(Active CPU 課金)。Node.js ランタイムのミドルウェアは Functions 課金が発生。
  • ミドルウェアは全リクエストの手前で動くので、重い処理を置かない。判定は軽く、データは Edge Config から。

可観測性

Observability でミドルウェアのパス別呼び出し・アクション内訳(リダイレクト/リライト)・リライト先の頻度を確認できます(Observability Plus でより詳細)。console.* API がフル対応なので、必要なログは Runtime Logs に出ます(可観測性)。


本番チェックリスト(Middleware)

  • ミドルウェアは軽い判定のみ(重処理・秘匿ロジックを置かない)
  • 認証ゲートは UX 最適化であり、最終認可はサーバー/DBで検証
  • フラグ/リダイレクト/IPリストは Edge Config(再デプロイ不要・低遅延)
  • ランタイムを用途で選択(Edge 既定 / Node.js は Functions 課金)
  • 大規模 bot/レート制限は WAF/BotID に委ねる
  • URL 14KB・body 4MB・ヘッダ制限を超えない
  • Observability でパス別の挙動を監視

まとめ

Routing Middleware は「ページの手前・キャッシュの前」という特等席で、認証・パーソナライズ・A/B・リダイレクトを実装できます。

  1. キャッシュを活かしたままパーソナライズできるのが最大の価値
  2. ランタイムは Edge 既定 / Node.js は Functions 課金
  3. データは Edge Config(低遅延・再デプロイ不要)
  4. 認可の最終確定はサーバー側、bot/レート制限は WAF
  5. 軽く保ち、Observability で監視

認証ゲート・多地域パーソナライズ・段階リリースの設計実装を、案件として承ります。

本記事は Routing Middleware / Edge Config 公式ドキュメント(2026年6月時点)に基づきます。仕様・上限は更新されるため、本番採用時は公式で最新値を確認してください。

友田

友田 陽大

経済産業大臣賞 受賞プロダクト開発者。TypeScript + Python + AWS で、SaaS・業界DX・ 実用レベルの生成AI(RAG)を、要件定義からインフラ・運用まで一人で完遂します。

この記事の実装を、案件として承ります

Vercel のアプリを、設計から本番運用・コスト最適化まで承ります

Fluid Compute を前提とした関数設計(グローバル状態の安全化・waitUntil・Cron)、4層キャッシュ(ISR/CDN/Runtime Cache/Cache Components)の設計、プレビュー/Promote/Instant Rollback/Rolling Releases の安全なデプロイ、Firewall/WAF/BotID の入口防御、Blob/Edge Config/Marketplace のストレージ選定、Active CPU 課金前提のコスト最適化まで。Next.js 製プロダクトを Vercel で本番運用してきた知見で、速く・安く・安全に伴走します。

プロジェクト単位(請負)・技術顧問のどちらにも対応可能です。まずは30分の無料技術相談から。

あわせて読みたい