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

参考资料