Geo-based routing in Next.js is implemented using Middleware which has access to the request's geo data (country, region, city) via request.geo on Vercel, or via third-party IP geolocation on self-hosted deployments. Middleware intercepts the request at the Edge and rewrites or redirects to country-specific pages — all before any HTML is rendered.
Geo-based routing is one of the most powerful use cases for Next.js Middleware. Because middleware runs at the Edge — physically close to the user — it can detect the user's location and make routing decisions with near-zero latency. The key distinction is between a rewrite (URL stays the same, different content served) and a redirect (URL changes to country-specific URL). Most production apps use rewrites for seamless UX and redirects for explicit locale routing.
request.geo.country — ISO 3166-1 alpha-2 country code (e.g. 'US', 'GB', 'DE')
request.geo.region — region/state code (e.g. 'CA' for California)
request.geo.city — city name (e.g. 'San Francisco')
request.geo.latitude — latitude coordinate
request.geo.longitude — longitude coordinate
request.ip — user IP address (for manual geolocation lookup)
geo data is provided by Vercel automatically — self-hosted needs manual IP lookup
Rewrite — URL stays the same (/pricing), different page renders — best for seamless UX
Rewrite — SEO sees one URL — simpler canonical URL management
Rewrite — user cannot share country-specific URL — always gets geo-detected version
Redirect — URL changes to /en-gb/pricing — explicit, shareable, bookmarkable
Redirect — better for i18n and multi-locale SEO with hreflang tags
Redirect — user can manually navigate to a different country URL
Best practice — use rewrite for invisible geo content swaps, redirect for explicit locale routing
request.geo is available automatically on Vercel — no setup needed
Self-hosted deployments need manual IP geolocation via third-party service or Cloudflare headers
Always provide a fallback country — geo detection can fail or return null
Use cookies to let users override geo detection — respect user preference over auto-detection
Inject country into request headers so Server Components can access geo data without re-detecting
Pre-build all country variants with generateStaticParams for maximum performance
Exclude _next/static and public assets from middleware matcher to avoid unnecessary processing
Use rewrites for invisible content swaps and redirects for explicit locale-based URL structures