Managing Redirects from your CMS using Vercel Bulk Redirects

Learn how to sync redirect rules from your CMS to Vercel at build time with vercel.ts, allowing non-technical teams to manage vanity URLs and product redirects without code changes.

Pranav Karthik
Ismael Rumzan
5 min read
Last updated January 10, 2026

Your e-commerce site needs /catalog/fall to point to different collections each year. Marketing runs campaigns with vanity URLs that need to update destinations weekly. Product SKUs get retired, but inbound links from blog posts and emails still need to work.

Currently, you either update redirects in middleware code (which needs developer resources for every change and adds additional computation at request time) or query your CMS at runtime (which adds latency to requests).Vercel bulk redirects solves this with:

  1. Build-time execution - Fetch redirects from your CMS during deployment, not on every request
  2. CDN-level handling - Redirects happen at Vercel’s CDN level in 5-10ms, before your application code runs

In this guide, you will implement bulk redirects by configuring vercel.ts .

  • Understanding bulk redirects with Vercel configuration
  • Hands-on setup with the cms-bulk-redirects example
  • Adapting the pattern to any CMS (Sanity, Strapi, etc.)

The deployment workflow with vercel.ts is as follows:

  1. The developer pushes code (or the CMS webhook triggers a deployment)
  2. The build process starts and runs vercel.ts
  3. vercel.ts fetches all redirect rules from your CMS
  4. The CMS returns redirect data
  5. vercel.ts generates a generated-redirects.json file
  6. Vercel publishes a deployment with redirects to CDN

Redirects now exist as static configuration in the CDN. When a user visits a path, Vercel’s CDN checks the redirect configuration and if there is a match, it redirects instantly

Build-time means you need to redeploy when redirects change. You can automate this by setting up a webhook in your CMS that triggers a Vercel deployment when redirect entries change. When your marketing team edits a redirect in your CMS and saves it, a new deployment starts automatically. We'll cover how to set this up later in the guide.

Here's how you tell Vercel to publish redirects at the CDN level:

vercel.ts
import type { VercelConfig } from '@vercel/config/v1'
export const config: VercelConfig = {
framework: 'nextjs',
outputDirectory: '.next',
bulkRedirectsPath: './generated-redirects.json', // This is the magic
}

In this example, we use Contentful as the CMS.

Setup (one time):

  • The marketing team creates a "redirect" content type in Contentful
  • The developer adds a webhook to trigger Vercel deployments on redirect changes

Every season:

  • The marketing team logs into Contentful
  • They create an entry: /catalog/fall/catalog/fall-2025, with status code 302
  • They save the entry
  • The webhook triggers a Vercel deployment
  • vercel.ts runs and fetches 100 redirects from Contentful
  • Vercel publishes redirects to the CDN across all regions

Customer experience:

  • A customer clicks a link in an email to /catalog/fall
  • The request hits the nearest Vercel CDN region
  • The CDN checks bulk redirects and finds a match
  • The CDN responds with 302 redirect in 5ms
  • Your Next.js app never executes
  • Your analytics show 0ms "server response time"
  • Node.js 20+ and pnpm installed
  • A Contentful account (free tier is sufficient)
  • Basic understanding of Next.js
terminal
pnpm create next-app --example https://github.com/vercel/examples/tree/main/cdn/cms-bulk-redirects
cd cms-bulk-redirects
pnpm install

You can also start from the template.

The demo includes fallback redirects, so you can explore it locally without CMS credentials: https://cms-bulk-redirects.vercel.app/

Start the development server:

terminal
pnpm dev

Visit http://localhost:3000 and try these paths:

  • /catalog/fall - redirects to /catalog/fall-2025
  • /catalog/latest - redirects to /catalog/spring-2026
  • /products/daybreak-pack - redirects to /catalog/limited-edition

Important: In development mode, Next.js handles these redirects through its dev server, not the CDN. This is just for local testing. In production on Vercel, these same rules run at the CDN level.

Open generated-redirects.json to see the fallback rules:

generated-redirects.json
[
{
"source": "/catalog/fall",
"destination": "/catalog/fall-2025",
"statusCode": 302
},
{
"source": "/catalog/latest",
"destination": "/catalog/spring-2026",
"permanent": true
}
]

These are static redirects for development. In production, they come from your CMS.

To see build-time execution in action, set up a real CMS. You can use the free tier of Contentful.

  1. Log into Contentful
  2. Go to Content model
  3. Add content type named "redirect"
  4. Add these fields:
Field NameTypeRequiredNotes
sourceShort textYese.g. /sale
destinationShort textYese.g. /catalog/archive
statusCodeNumberNoDefault: 302
permanentBooleanNoIf true, uses 301
caseSensitiveBooleanNoDefault: false
preserveQueryBooleanNoPass query params
  • source: /sale
  • destination: /catalog/archive
  • statusCode: 302

Save and publish the entry.

Create a .env.local file:

.env.local
CONTENTFUL_SPACE_ID=your_space_id
CONTENTFUL_ACCESS_TOKEN=your_cda_token

Find these values in Contentful:

  • Space ID: Settings → General settings
  • Access Token: Settings → API keys → Content Delivery API

Run a production build to see vercel.ts fetch redirects from your CMS:

terminal
pnpm build

Watch the console output:

terminal
> next build
fetching contentful redirects
✓ Bulk redirects ready (34 rules) -> /generated-redirects.json

The CMS fetch happened at build time. Open generated-redirects.json to see your CMS data as a static file.

Now test the redirects:

terminal
pnpm dev

Visit http://localhost:3000/sale to test your redirect.

Deploy to see CDN-level redirects in action:

terminal
vercel --prod

Or connect your GitHub repository in the Vercel dashboard and add the environment variables in project settings.

After deployment, test a redirect URL. Open your browser's network tab and visit your deployed URL with a redirect path like /sale.

This is build-time execution in action. The file runs once during deployment, not on every request.

The pattern works with any CMS. You only need to change the fetch function.

sanity-fetch.ts
import { createClient } from '@sanity/client'
async function fetchSanityRedirects(): Promise<VercelRedirect[]> {
const client = createClient({
projectId: process.env.SANITY_PROJECT_ID,
dataset: process.env.SANITY_DATASET,
apiVersion: '2024-01-01',
useCdn: false,
})
const query = '*[_type == "redirect"]{ source, destination, statusCode, permanent }'
const redirects = await client.fetch(query)
return redirects.map((redirect) => ({
source: normalizePath(redirect.source),
destination: normalizePath(redirect.destination),
statusCode: redirect.statusCode,
permanent: redirect.permanent,
}))
}
strapi-fetch.ts
async function fetchStrapiRedirects(): Promise<VercelRedirect[]> {
const response = await fetch(`${process.env.STRAPI_URL}/api/redirects`, {
headers: {
Authorization: `Bearer ${process.env.STRAPI_TOKEN}`,
},
})
const { data } = await response.json()
return data.map((item) => ({
source: normalizePath(item.attributes.source),
destination: normalizePath(item.attributes.destination),
statusCode: item.attributes.statusCode,
permanent: item.attributes.permanent,
}))
}

Set up CMS webhooks to trigger Vercel deployments when redirects change. In Contentful:

  1. Settings → Webhooks → Add webhook
  2. Trigger on: Entry publish/unpublish for "redirect" content type
  3. URL: Your Vercel deploy hook (Project Settings → Git → Deploy Hooks)

Add redirect validation in vercel.ts to catch errors at build time:

vercel.ts
function validateRedirects(redirects: VercelRedirect[]): void {
const sources = new Set<string>()
for (const redirect of redirects) {
// Check for duplicates
if (sources.has(redirect.source)) {
throw new Error(`Duplicate source path: ${redirect.source}`)
}
sources.add(redirect.source)
// Check for circular redirects
const destinations = redirects.map(r => r.source)
if (destinations.includes(redirect.destination)) {
console.warn(`⚠️ Potential circular redirect: ${redirect.source}${redirect.destination}`)
}
}
}
  • Set up a working example that demonstrates redirects set up at build time and running at the CDN level
  • Explored how vercel.ts fetches from your CMS at build time and configures CDN redirects

Was this helpful?

supported.
Managing Redirects from your CMS using Vercel Bulk Redirects | Vercel Knowledge Base