routing-middleware

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Vercel Routing Middleware

Vercel Routing Middleware

You are an expert in Vercel Routing Middleware — the platform-level request interception layer.
您是 Vercel Routing Middleware 的专家——这是平台级别的请求拦截层。

What It Is

什么是 Vercel Routing Middleware

Routing Middleware runs before the cache on every request matching its config. It is a Vercel platform feature (not framework-specific) that works with Next.js, SvelteKit, Astro, Nuxt, or any deployed framework. Built on Fluid Compute.
  • File:
    middleware.ts
    or
    middleware.js
    at the project root
  • Default export required (function name can be anything)
  • Runtimes: Edge (default), Node.js (
    runtime: 'nodejs'
    ), Bun (Node.js +
    bunVersion
    in vercel.json)
Routing Middleware 会在缓存之前,对所有匹配其配置的请求运行。它是一项Vercel 平台功能(不绑定特定框架),可与 Next.js、SvelteKit、Astro、Nuxt 或任何已部署的框架配合使用,基于 Fluid Compute 构建。
  • 文件位置:项目根目录下的
    middleware.ts
    middleware.js
  • 必须默认导出(函数名称可自定义)
  • 支持的运行时:Edge(默认)、Node.js(需配置
    runtime: 'nodejs'
    )、Bun(基于 Node.js 配置,需在 vercel.json 中指定
    bunVersion

CRITICAL: Middleware Disambiguation

关键说明:Middleware 概念区分

There are THREE "middleware" concepts in the Vercel ecosystem:
ConceptFileRuntimeScopeWhen to Use
Vercel Routing Middleware
middleware.ts
(root)
Edge/Node/BunAny framework, platform-levelRequest interception before cache: rewrites, redirects, geo, A/B
Next.js 16 Proxy
proxy.ts
(root, or
src/proxy.ts
if using
--src-dir
)
Node.js onlyNext.js 16+ onlyNetwork-boundary proxy needing full Node APIs. NOT for auth.
Edge FunctionsAny function fileV8 isolatesGeneral-purposeStandalone edge compute endpoints, not an interception layer
Why the rename in Next.js 16:
middleware.ts
proxy.ts
clarifies it sits at the network boundary (not general-purpose middleware). Partly motivated by CVE-2025-29927 (middleware auth bypass via
x-middleware-subrequest
header). The exported function must also be renamed from
middleware
to
proxy
. Migration codemod:
npx @next/codemod@latest middleware-to-proxy
Deprecation: Next.js 16 still accepts
middleware.ts
but treats it as deprecated and logs a warning. It will be removed in a future version.
Vercel 生态中有三种“middleware”概念:
概念文件运行时适用范围使用场景
Vercel Routing Middleware根目录下的
middleware.ts
Edge/Node/Bun任意框架,平台级别缓存前的请求拦截:重写、重定向、地域适配、A/B 测试
Next.js 16 Proxy根目录(或使用
--src-dir
时为
src/proxy.ts
)下的
proxy.ts
仅支持 Node.js仅 Next.js 16+需要完整 Node API 的网络边界代理。不用于认证
Edge Functions任意函数文件V8 隔离环境通用场景独立的边缘计算端点,非请求拦截层
Next.js 16 重命名原因
middleware.ts
改为
proxy.ts
是为了明确其位于网络边界(而非通用 middleware)。部分原因是受 CVE-2025-29927 漏洞(通过
x-middleware-subrequest
头绕过 middleware 认证)的影响。导出函数也必须从
middleware
重命名为
proxy
。迁移代码修改工具:
npx @next/codemod@latest middleware-to-proxy
弃用说明:Next.js 16 仍接受
middleware.ts
,但会将其标记为已弃用并记录警告,未来版本将移除该支持。

Bun Runtime

Bun 运行时配置

To run Routing Middleware (and all Vercel Functions) on Bun, add
bunVersion
to
vercel.json
:
json
{
  "bunVersion": "1.x"
}
Set the middleware runtime to
nodejs
— Bun replaces the Node.js runtime transparently:
ts
export const config = {
  runtime: 'nodejs', // Bun swaps in when bunVersion is set
};
Bun reduces average latency by ~28% in CPU-bound workloads. Currently in Public Beta — supports Next.js, Express, Hono, and Nitro.
要在 Bun 上运行 Routing Middleware(及所有 Vercel Functions),需在
vercel.json
中添加
bunVersion
json
{
  "bunVersion": "1.x"
}
将 middleware 运行时设置为
nodejs
——Bun 会自动替换 Node.js 运行时:
ts
export const config = {
  runtime: 'nodejs', // 当配置 bunVersion 后,Bun 会自动替换
};
在 CPU 密集型工作负载中,Bun 可将平均延迟降低约 28%。目前处于公开测试阶段——支持 Next.js、Express、Hono 和 Nitro。

Basic Example

基础示例

ts
// middleware.ts (project root)
import { geolocation, rewrite } from '@vercel/functions';

export default function middleware(request: Request) {
  const { country } = geolocation(request);
  const url = new URL(request.url);
  url.pathname = country === 'US' ? '/us' + url.pathname : '/intl' + url.pathname;
  return rewrite(url);
}

export const config = {
  runtime: 'edge', // 'edge' (default) | 'nodejs'
};
ts
// middleware.ts(项目根目录)
import { geolocation, rewrite } from '@vercel/functions';

export default function middleware(request: Request) {
  const { country } = geolocation(request);
  const url = new URL(request.url);
  url.pathname = country === 'US' ? '/us' + url.pathname : '/intl' + url.pathname;
  return rewrite(url);
}

export const config = {
  runtime: 'edge', // 'edge'(默认)| 'nodejs'
};

Helper Methods (
@vercel/functions
)

辅助方法(
@vercel/functions

For non-Next.js frameworks, import from
@vercel/functions
:
HelperPurpose
next()
Continue middleware chain (optionally modify headers)
rewrite(url)
Transparently serve content from a different URL
geolocation(request)
Get
city
,
country
,
latitude
,
longitude
,
region
ipAddress(request)
Get client IP address
waitUntil(promise)
Keep function running after response is sent
For Next.js, equivalent helpers are on
NextResponse
(
next()
,
rewrite()
,
redirect()
) and
NextRequest
(
request.geo
,
request.ip
).
对于非 Next.js 框架,可从
@vercel/functions
导入以下方法:
辅助方法用途
next()
继续 middleware 链(可选择性修改请求头)
rewrite(url)
透明地从其他 URL 提供内容
geolocation(request)
获取
city
country
latitude
longitude
region
信息
ipAddress(request)
获取客户端 IP 地址
waitUntil(promise)
在响应发送后保持函数运行
对于 Next.js,等效的辅助方法位于
NextResponse
next()
rewrite()
redirect()
)和
NextRequest
request.geo
request.ip
)上。

Matcher Configuration

匹配规则配置

Middleware runs on every route by default. Use
config.matcher
to scope it:
ts
// Single path
export const config = { matcher: '/dashboard/:path*' };

// Multiple paths
export const config = { matcher: ['/dashboard/:path*', '/api/:path*'] };

// Regex: exclude static files
export const config = {
  matcher: ['/((?!_next/static|favicon.ico).*)'],
};
Tip: Using
matcher
is preferred — unmatched paths skip middleware invocation entirely (saves compute).
默认情况下,Middleware 会在所有路由上运行。可使用
config.matcher
来限定其作用范围:
ts
// 单个路径
export const config = { matcher: '/dashboard/:path*' };

// 多个路径
export const config = { matcher: ['/dashboard/:path*', '/api/:path*'] };

// 正则表达式:排除静态文件
export const config = {
  matcher: ['/((?!_next/static|favicon.ico).*)'],
};
提示:推荐使用
matcher
——不匹配的路径会完全跳过 middleware 调用(节省计算资源)。

Common Patterns

常见使用模式

IP-Based Header Injection

基于 IP 的请求头注入

ts
import { ipAddress, next } from '@vercel/functions';

export default function middleware(request: Request) {
  return next({ headers: { 'x-real-ip': ipAddress(request) || 'unknown' } });
}
ts
import { ipAddress, next } from '@vercel/functions';

export default function middleware(request: Request) {
  return next({ headers: { 'x-real-ip': ipAddress(request) || 'unknown' } });
}

A/B Testing via Edge Config

借助 Edge Config 实现 A/B 测试

ts
import { get } from '@vercel/edge-config';
import { rewrite } from '@vercel/functions';

export default async function middleware(request: Request) {
  const variant = await get('experiment-homepage'); // <1ms read
  const url = new URL(request.url);
  url.pathname = variant === 'B' ? '/home-b' : '/home-a';
  return rewrite(url);
}
ts
import { get } from '@vercel/edge-config';
import { rewrite } from '@vercel/functions';

export default async function middleware(request: Request) {
  const variant = await get('experiment-homepage'); // 读取耗时 <1ms
  const url = new URL(request.url);
  url.pathname = variant === 'B' ? '/home-b' : '/home-a';
  return rewrite(url);
}

Background Processing

后台处理

ts
import type { RequestContext } from '@vercel/functions';

export default function middleware(request: Request, context: RequestContext) {
  context.waitUntil(
    fetch('https://analytics.example.com/log', { method: 'POST', body: request.url })
  );
  return new Response('OK');
}
ts
import type { RequestContext } from '@vercel/functions';

export default function middleware(request: Request, context: RequestContext) {
  context.waitUntil(
    fetch('https://analytics.example.com/log', { method: 'POST', body: request.url })
  );
  return new Response('OK');
}

Request Limits

请求限制

LimitValue
Max URL length14 KB
Max request body4 MB
Max request headers64 headers / 16 KB total
限制项数值
最大 URL 长度14 KB
最大请求体大小4 MB
最大请求头数量64 个请求头 / 总大小 16 KB

Three CDN Routing Mechanisms

三种 CDN 路由机制

Vercel's CDN supports three routing mechanisms, evaluated in this order:
OrderMechanismScopeDeploy RequiredHow to Configure
1Bulk RedirectsUp to 1M static path→path redirectsNo (runtime via Dashboard/API/CLI)Dashboard, CSV upload, REST API
2Project-Level RoutesHeaders, rewrites, redirectsNo (instant publish)Dashboard, API, CLI, Vercel SDK
3Deployment Config RoutesFull routing rulesYes (deploy)
vercel.json
,
vercel.ts
,
next.config.ts
Project-level routes (added March 2026) let you update routing rules — response headers, rewrites to external APIs — without triggering a new deployment. They run after bulk redirects and before deployment config routes. Available on all plans.
Vercel CDN 支持三种路由机制,按以下顺序执行:
顺序机制适用范围是否需要部署配置方式
1批量重定向最多 100 万条静态路径→路径重定向无需部署(通过控制台/API/CLI 实时生效)控制台、CSV 上传、REST API
2项目级路由请求头、重写、重定向无需部署(即时发布)控制台、API、CLI、Vercel SDK
3部署配置路由完整路由规则需要部署
vercel.json
vercel.ts
next.config.ts
项目级路由(2026 年 3 月推出)允许您更新路由规则——响应头、外部 API 重写——无需触发新部署。它在批量重定向之后、部署配置路由之前运行,所有套餐均支持。

Project-Level Routes — Configuration Methods

项目级路由——配置方式

Project-level routes take effect instantly (no deploy required). Four ways to manage them:
MethodHow
DashboardProject → CDN → Routing tab. Live map of global traffic, cache management, and route editor in one view.
REST API
GET/POST/PATCH/DELETE /v1/projects/{projectId}/routes
— 8 dedicated endpoints for CRUD on project routes.
Vercel CLIManaged via
vercel.ts
/
@vercel/config
commands (
compile
,
validate
,
generate
).
Vercel SDK
@vercel/config
helpers:
routes.redirect()
,
routes.rewrite()
,
routes.header()
, plus
has
/
missing
conditions and transforms.
Use project-level routes for operational changes (CORS headers, API proxy rewrites, A/B redirects) that shouldn't require a full redeploy.
项目级路由即时生效(无需部署),有四种管理方式:
方式操作说明
控制台项目 → CDN → 路由标签页。可查看全球流量实时地图、缓存管理和路由编辑器。
REST API
GET/POST/PATCH/DELETE /v1/projects/{projectId}/routes
——8 个专用端点用于项目路由的增删改查。
Vercel CLI通过
vercel.ts
/
@vercel/config
命令管理(
compile
validate
generate
)。
Vercel SDK
@vercel/config
辅助方法:
routes.redirect()
routes.rewrite()
routes.header()
,以及
has
/
missing
条件和转换规则。
项目级路由适用于无需完整重新部署的运维变更(CORS 头、API 代理重写、A/B 测试重定向)。

Programmatic Configuration with
vercel.ts

使用
vercel.ts
进行程序化配置

Instead of static
vercel.json
, you can use
vercel.ts
(or
.js
,
.mjs
,
.cjs
,
.mts
) with the
@vercel/config
package for type-safe, dynamic routing configuration:
ts
// vercel.ts
import { defineConfig } from '@vercel/config';

export default defineConfig({
  rewrites: [
    { source: '/api/:path*', destination: 'https://backend.example.com/:path*' },
  ],
  headers: [
    { source: '/(.*)', headers: [{ key: 'X-Frame-Options', value: 'DENY' }] },
  ],
});
CLI commands:
  • npx @vercel/config compile
    — compile to JSON (stdout)
  • npx @vercel/config validate
    — validate and show summary
  • npx @vercel/config generate
    — generate
    vercel.json
    locally for development
Constraint: Only one config file per project —
vercel.json
or
vercel.ts
, not both.
除了静态的
vercel.json
,您还可以使用
vercel.ts
(或
.js
.mjs
.cjs
.mts
)配合
@vercel/config
包,实现类型安全的动态路由配置:
ts
// vercel.ts
import { defineConfig } from '@vercel/config';

export default defineConfig({
  rewrites: [
    { source: '/api/:path*', destination: 'https://backend.example.com/:path*' },
  ],
  headers: [
    { source: '/(.*)', headers: [{ key: 'X-Frame-Options', value: 'DENY' }] },
  ],
});
CLI 命令:
  • npx @vercel/config compile
    ——编译为 JSON 格式(输出到标准输出)
  • npx @vercel/config validate
    ——验证配置并显示摘要
  • npx @vercel/config generate
    ——在本地生成
    vercel.json
    用于开发
约束:每个项目仅能使用一个配置文件——
vercel.json
vercel.ts
,不可同时使用。

When to Use

适用场景

  • Geo-personalization of static pages (runs before cache)
  • A/B testing rewrites with Edge Config
  • Custom redirects based on request properties
  • Header injection (CSP, CORS, custom headers)
  • Lightweight auth checks (defense-in-depth only — not sole auth layer)
  • Project-level routes for headers/rewrites without redeploying
  • 静态页面的地域个性化处理(在缓存前运行)
  • 借助 Edge Config 实现 A/B 测试重写
  • 基于请求属性的自定义重定向
  • 请求头注入(CSP、CORS、自定义请求头)
  • 轻量级认证检查(仅作为纵深防御——不可作为唯一认证层)
  • 使用项目级路由配置请求头/重写,无需重新部署

When NOT to Use

不适用场景

  • Need full Node.js APIs in Next.js → use
    proxy.ts
  • General compute at the edge → use Edge Functions
  • Heavy business logic or database queries → use server-side framework features
  • Auth as sole protection → use Layouts, Server Components, or Route Handlers
  • Thousands of static redirects → use Bulk Redirects (up to 1M per project)
  • Next.js 中需要完整 Node.js API → 使用
    proxy.ts
  • 通用边缘计算 → 使用 Edge Functions
  • 复杂业务逻辑或数据库查询 → 使用服务端框架特性
  • 认证作为唯一保护机制 → 使用布局组件、服务端组件或路由处理器
  • 数千条静态重定向 → 使用批量重定向(每个项目最多支持 100 万条)

References

参考资料