TemperStack
Intermediate8 min readUpdated Mar 18, 2026

How to configure geo routing with middleware on Vercel

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

  1. Vercel account with active project
  2. Basic knowledge of Next.js middleware
  3. Understanding of HTTP requests and geography-based routing
  4. Node.js development environment
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).*)'
}
Tip
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}`)
}
Tip
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))
}
Tip
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
}
Tip
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.
Tip
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
}
Tip
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.
Tip
Use Vercel Analytics to monitor the effectiveness of your geo routing strategy

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.

Related Guides

More Vercel Tutorials

Other Tool Tutorials

Ready to get started with Vercel?

Put this tutorial into practice. Visit Vercel and follow the steps above.

Visit Vercel