Перейти к основному содержимому
友田 陽大
Vercel in production
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まで実コードで解説します。

Published
Reading time
7 min read
Author
友田 陽大
Поделиться

「ログインしていないユーザーを /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月時点)に基づきます。仕様・上限は更新されるため、本番採用時は公式で最新値を確認してください。

友田

友田 陽大

Разработчик продукта, отмеченного премией Министра (METI). На TypeScript + Python + AWS создаю SaaS, цифровизацию промышленности и готовый к продакшену генеративный ИИ (RAG) — от требований до инфраструктуры и эксплуатации, в одиночку.

I can take on the implementation from this article as an engagement

Vercel apps, from design to production and cost optimization

Function design assuming Fluid Compute (safe global state, waitUntil, Cron), four-layer caching (ISR/CDN/Runtime Cache/Cache Components), safe deploys (preview/Promote/Instant Rollback/Rolling Releases), entry-point defense (Firewall/WAF/BotID), storage selection (Blob/Edge Config/Marketplace), and Active-CPU-billing-aware cost optimization. With experience running Next.js products on Vercel in production, I deliver fast, cheap, and secure.

Доступен как для проектной работы, так и для технического консультирования. Начните с бесплатной 30-минутной консультации.

最短ルート:カレンダーから直接予約

相談内容が固まっている方は、フォーム送信よりその場で日程を確定する方がスムーズです。下記から空き時間をお選びください。

  • 30分のオンライン無料相談
  • Google Meet / Zoom / Microsoft Teams
  • NDA 商談前締結可・無理な営業はいたしません
無料相談の空き枠を予約する

Также стоит прочитать