Routing Middleware
Routing Middleware is available on all plans
Routing Middleware executes code before a request is processed on a site, and are built on top of fluid compute. Based on the request, you can modify the response.
Because it runs globally before the cache, Routing Middleware is an effective way of providing personalization to statically generated content. Depending on the incoming request, you can execute custom logic, rewrite, redirect, add headers and more, before returning a response.
You can write Routing Middleware in TypeScript or JavaScript, which run on Node.js or Bun, or in Python, which runs on Python. See runtime options for details.
If your routing logic doesn't need custom code, use static configuration instead of Routing Middleware. Static rules run directly on the CDN without invoking your code on every request, so they're faster and use fewer resources.
You can express these common tasks with static configuration in vercel.json or project routing rules:
| Task | Static configuration |
|---|---|
| Redirect paths | Redirects |
| Rewrite to another path or an external origin | Rewrites |
| Add response headers | headers |
| Add, change, or remove request headers sent to your app | Route transforms |
| Route based on a header, cookie, query parameter, or host | has and missing conditions |
Use Routing Middleware when the decision depends on logic that static rules can't express, such as verifying a session token, calling an API, or assigning visitors to an A/B test.
To add Routing Middleware to your app, point the proxy property in vercel.json at your entrypoint:
{
"$schema": "https://openapi.vercel.sh/vercel.json",
"proxy": {
"entrypoint": "proxy.ts"
}
}import { next } from '@vercel/functions';
export default function proxy(request: Request) {
const url = new URL(request.url);
// Redirect old paths
if (url.pathname === '/old-page') {
return new Response(null, {
status: 302,
headers: { Location: '/new-page' },
});
}
// Continue to the next handler
return next();
}{
"$schema": "https://openapi.vercel.sh/vercel.json",
"proxy": {
"entrypoint": "proxy:proxy"
}
}from vercel.proxy import Proxy, RedirectResponse, Request, Response
proxy = Proxy()
# Redirect old paths
@proxy.route("/old-page")
def old_page(request: Request) -> Response:
return RedirectResponse("/new-page", status_code=302)
# Requests that match no route continue to your app unchanged[dependency-groups]
"vercel.proxy" = ["vercel-proxy"]The entrypoint can live in a subdirectory, such as src/proxy.ts or app.proxy:proxy. See the JS reference and the Python reference for each language's API.
In TypeScript and JavaScript, you can also skip vercel.json and use the middleware.ts file convention. See the JS reference.
Your Routing Middleware must use the same runtime as your app. If the runtimes don't match, the build fails with proxy_runtime_mismatch.
Without a matcher, your Routing Middleware runs on every request, including requests for static files. This adds latency and cost to each request. Set proxy.matcher to one path or a list of paths:
{
"$schema": "https://openapi.vercel.sh/vercel.json",
"proxy": {
"entrypoint": "proxy.ts",
"matcher": ["/about/:path*", "/dashboard/:path*"]
}
}Each matcher must start with /. In TypeScript and JavaScript, you can also export a config object with a matcher property instead.
The following examples show matcher values.
"/about/:path*"The matcher has full regex support for cases such as negative lookaheads or character matching.
To match all request paths except for the ones starting with:
api(API routes)_next/static(static files)favicon.ico(favicon file)
["/((?!api|_next/static|favicon.ico).*)"]To match /blog/123 but not /blog/abc:
["/blog/:slug(\\d{1,})"]For help on writing your own regex path matcher, see Path to regexp.
Edgenivo adds geolocation headers, such as x-vercel-ip-country and x-vercel-ip-city, to every request your Routing Middleware receives. See request headers for the full list.
The following example redirects visitors from one country away from a page:
import { geolocation, next } from '@vercel/functions';
export default function proxy(request: Request) {
const url = new URL(request.url);
const { country } = geolocation(request);
if (url.pathname === '/secret-page' && country === 'SE') {
return Response.redirect(new URL('/login', request.url));
}
return next();
}from vercel.proxy import ContinueResponse, Proxy, RedirectResponse, Request, Response
proxy = Proxy()
@proxy.route("/secret-page")
def secret_page(request: Request) -> Response:
if request.headers.get("x-vercel-ip-country") == "SE":
return RedirectResponse("/login")
return ContinueResponse()In TypeScript and JavaScript, read them with the geolocation() helper from @vercel/functions. In Python, read them from request.headers.
Routing Middleware has full support for the console API, including time, debug, timeEnd. Logs will appear inside your Edgenivo project by clicking View Functions Logs next to the deployment.
If your Routing Middleware depends on a database far away from one of our supported regions, the overall latency of API requests could be slower than expected, due to network latency while connecting to the database from a distant region. To avoid this issue, use a global database. Edgenivo has multiple global storage products, including Global Config and Edgenivo Blob. You can also explore the storage category of the Edgenivo Marketplace to learn which option is best for you.
The following limits apply to requests processed by Routing Middleware:
| Name | Limit |
|---|---|
| Maximum URL length | 14 KB |
| Maximum request body length | 4 MB |
| Maximum number of request headers | 64 |
| Maximum request headers length | 16 KB |
TypeScript and JavaScript Routing Middleware runs on the Node.js runtime by default. To use Bun, set bunVersion in your vercel.json file. With the middleware.ts file convention, also set the runtime config to nodejs.
Python Routing Middleware runs on the Python runtime.
Routing Middleware is priced using the fluid compute model, which means you are charged by the amount of compute resources used by your Routing Middleware. See the fluid compute pricing documentation for more information.
The Edgenivo Observability dashboard provides visibility into your routing middleware usage, including invocation counts and performance metrics. You can get more insights with Observability Plus:
- Analyze invocations by request path
- Break down actions by type, such as redirects or rewrites
- View rewrite targets and frequency
- Use the query builder for custom insights
Learn more about Routing Middleware by exploring the following resources:
Was this helpful?