V Vercel

How to configure geo routing with middleware on Vercel

intermediate 8 min read Updated 2026-04-20
Quick Answer

Configure geo routing on Vercel by creating middleware that reads the country code from request headers and redirects users based on their location. Use Vercel's built-in geo headers to implement country-specific routing rules.

Prerequisites

  • Vercel account with active project
  • Basic knowledge of Next.js middleware
  • Understanding of HTTP requests and geography-based routing
  • Node.js development environment

Step-by-Step Instructions

1

Create the middleware file

In your project root, create a middleware.js or middleware.ts file. This file will intercept all incoming requests before they reach your pages.

// middleware.js
import { NextResponse } from 'next/server'

export function middleware(request) {
  // Middleware logic will go here
}

export const config = {
  matcher: '/((?!api|_next/static|_next/image|favicon.ico).*)'
}
Place the middleware file at the project root level, not inside the pages or app directory
2

Access geo location data

Use Vercel's built-in geo headers to detect user location. The request.geo object contains country, region, and city information.

export function middleware(request) {
  const country = request.geo?.country || 'US'
  const region = request.geo?.region
  const city = request.geo?.city
  
  console.log(`User from: ${city}, ${region}, ${country}`)
}
Vercel automatically populates geo data - no additional setup required for basic location detection
3

Define routing rules

Create routing logic based on country codes. Set up redirects or rewrites for different geographical regions.

export function middleware(request) {
  const country = request.geo?.country || 'US'
  const { pathname } = request.nextUrl
  
  // Skip if already on a geo-specific path
  if (pathname.startsWith('/us') || pathname.startsWith('/eu') || pathname.startsWith('/asia')) {
    return NextResponse.next()
  }
  
  // Define country-to-region mapping
  const euCountries = ['DE', 'FR', 'IT', 'ES', 'NL', 'GB']
  const asiaCountries = ['JP', 'CN', 'IN', 'SG', 'KR']
  
  if (euCountries.includes(country)) {
    return NextResponse.redirect(new URL(`/eu${pathname}`, request.url))
  } else if (asiaCountries.includes(country)) {
    return NextResponse.redirect(new URL(`/asia${pathname}`, request.url))
  }
  
  // Default to US
  return NextResponse.redirect(new URL(`/us${pathname}`, request.url))
}
Use ISO 3166-1 alpha-2 country codes (like 'US', 'GB', 'DE') for consistency
4

Handle language preferences

Combine geo routing with language detection from the Accept-Language header for more sophisticated routing.

export function middleware(request) {
  const country = request.geo?.country || 'US'
  const acceptLanguage = request.headers.get('accept-language') || ''
  const { pathname } = request.nextUrl
  
  // Extract preferred language
  const preferredLang = acceptLanguage.split(',')[0]?.split('-')[0] || 'en'
  
  // Route based on country and language
  if (country === 'DE') {
    const lang = preferredLang === 'de' ? 'de' : 'en'
    return NextResponse.redirect(new URL(`/${lang}/de${pathname}`, request.url))
  }
  
  // Add similar logic for other countries
}
Always provide fallback languages to ensure users can access your content
5

Create geo-specific pages

Organize your pages directory to match your routing structure. Create folders for each geographical region.

pages/
├── us/
│   ├── index.js
│   └── about.js
├── eu/
│   ├── index.js
│   └── about.js
├── asia/
│   ├── index.js
│   └── about.js
└── index.js (fallback)


Each regional page can contain location-specific content, pricing, or features.
Consider using dynamic imports to load region-specific components and reduce bundle size
6

Add bypass mechanism

Implement a way for users to override geo routing using URL parameters or cookies for testing and user preference.

export function middleware(request) {
  const { searchParams, pathname } = request.nextUrl
  const country = request.geo?.country || 'US'
  
  // Check for region override
  const regionOverride = searchParams.get('region')
  const cookieRegion = request.cookies.get('preferred-region')?.value
  
  if (regionOverride && ['us', 'eu', 'asia'].includes(regionOverride)) {
    const response = NextResponse.redirect(new URL(`/${regionOverride}${pathname}`, request.url))
    response.cookies.set('preferred-region', regionOverride, { maxAge: 86400 * 30 })
    return response
  }
  
  if (cookieRegion) {
    return NextResponse.redirect(new URL(`/${cookieRegion}${pathname}`, request.url))
  }
  
  // Continue with geo-based routing
}
Use query parameters like ?region=eu for easy testing during development
7

Deploy and test

Deploy your changes to Vercel and test geo routing functionality. Use Vercel's Edge Network to verify routing from different locations.

Test using:
  • Vercel CLI: vercel dev for local testing
  • Browser DevTools: Override headers in Network tab
  • VPN services: Test from different geographical locations
  • Vercel Edge Functions: Check logs in dashboard

Monitor the Functions tab in your Vercel dashboard to see middleware execution logs.
Use Vercel Analytics to monitor the effectiveness of your geo routing strategy

Common Issues & Troubleshooting

Middleware not executing or geo data is undefined

Ensure your middleware file is in the project root and check that you're on a Vercel Pro plan or higher. Geo data is only available on Edge Runtime, verify your config.runtime is not set to Node.js.

Infinite redirect loops occurring

Add proper path checks to prevent redirecting already geo-routed URLs. Use pathname.startsWith('/us') conditions to exit early when users are already on the correct regional path.

Geo routing not working in development

Geo headers are only available in production on Vercel. For local testing, mock the geo data by setting default values: const country = request.geo?.country || 'US' or use the Vercel CLI with --prod flag.

SEO issues with geo redirects

Use NextResponse.rewrite() instead of redirect() for better SEO, or implement proper canonical tags and hreflang attributes. Consider using 302 status codes for temporary geo-based redirects.

Prices mentioned in this guide are pulled from current plan data and may change. Always verify on the official Vercel website before purchasing.