📝 PENDING APPROVAL
This article is published and accessible via direct link (for review), but will NOT appear in Google search results, sitemap, or category pages until approved. Click the button below to approve and make this article discoverable.
✓ Approve & Add to Sitemap
Next.js + Vercel Stack6 min read

Next.js Edge Runtime API Routes: When and How to Use Them

Learn to implement Next.js Edge Runtime API routes with practical examples for geolocation, A/B testing, and rate limiting. Includes migration guide from Node.js runtime.

By John Hashem

Next.js Edge Runtime API routes run at the edge of Vercel's global network, bringing your API logic closer to users worldwide. Unlike traditional Node.js runtime routes that execute on a single server, Edge Runtime routes deploy to dozens of locations simultaneously, reducing latency and improving performance for geographically distributed users.

This tutorial walks you through implementing Edge Runtime API routes, covering practical use cases like geolocation-based responses, A/B testing, and request filtering. You'll also learn when Edge Runtime makes sense for your application and how to migrate existing Node.js routes.

Understanding Edge Runtime vs Node.js Runtime

Edge Runtime uses a subset of Web APIs rather than the full Node.js environment. This constraint enables faster cold starts and global distribution, but limits available libraries and APIs. Edge functions typically start in under 50ms compared to 200-500ms for Node.js functions.

The runtime supports standard Web APIs like fetch, Request, Response, and URL, but excludes Node.js-specific modules like fs, path, or most npm packages that depend on Node.js internals. This trade-off makes Edge Runtime ideal for lightweight operations that benefit from low latency.

When to Use Edge Runtime API Routes

Edge Runtime excels in specific scenarios where speed and global distribution matter more than complex processing capabilities.

Geographic Content Delivery

Serving different content based on user location becomes trivial with Edge Runtime. The request.geo object provides country, region, and city information without external API calls.

A/B Testing and Feature Flags

Edge functions can modify responses, redirect users, or inject different content based on cookies or headers. This happens before your main application loads, reducing perceived load time.

Authentication and Rate Limiting

Simple authentication checks and rate limiting work well at the edge. You can validate JWT tokens, check API keys, or implement basic rate limiting without hitting your main database.

Request Filtering and Validation

Edge functions can filter malicious requests, validate input formats, or block traffic from specific regions before it reaches your application servers.

Prerequisites

Before starting, ensure you have:

  • Next.js 13+ project with App Router
  • Vercel account for deployment
  • Basic understanding of API routes in Next.js

Step 1: Create Your First Edge Runtime API Route

Create a new API route file in your Next.js project. The key difference is adding the runtime export set to 'edge'.

// app/api/edge-demo/route.js
export const runtime = 'edge'

export async function GET(request) {
  return new Response(
    JSON.stringify({
      message: 'Hello from Edge Runtime',
      timestamp: new Date().toISOString(),
      region: process.env.VERCEL_REGION || 'development'
    }),
    {
      status: 200,
      headers: {
        'Content-Type': 'application/json',
      },
    }
  )
}

This basic example demonstrates the Web API approach. Instead of Express-style req and res objects, you work with Request and Response objects that match browser standards.

Step 2: Implement Geolocation-Based Responses

Edge Runtime provides built-in geolocation data through the request object. Here's how to serve location-specific content:

// app/api/geo-content/route.js
export const runtime = 'edge'

export async function GET(request) {
  const country = request.geo?.country || 'Unknown'
  const city = request.geo?.city || 'Unknown'
  
  // Serve different content based on location
  const content = {
    US: { currency: 'USD', language: 'en-US', timezone: 'America/New_York' },
    GB: { currency: 'GBP', language: 'en-GB', timezone: 'Europe/London' },
    DE: { currency: 'EUR', language: 'de-DE', timezone: 'Europe/Berlin' },
    default: { currency: 'USD', language: 'en-US', timezone: 'UTC' }
  }
  
  const localeData = content[country] || content.default
  
  return Response.json({
    location: { country, city },
    ...localeData,
    detectedAt: 'edge'
  })
}

This pattern works excellently for e-commerce sites that need to show appropriate currencies, languages, or shipping options based on user location.

Step 3: Build an A/B Testing System

Edge Runtime can implement A/B testing by examining cookies and modifying responses accordingly:

// app/api/ab-test/route.js
export const runtime = 'edge'

export async function GET(request) {
  const url = new URL(request.url)
  const cookies = request.headers.get('cookie') || ''
  
  // Check for existing test assignment
  let variant = 'A'
  const existingVariant = cookies.match(/ab_test=([AB])/)
  
  if (existingVariant) {
    variant = existingVariant[1]
  } else {
    // Assign new variant (50/50 split)
    variant = Math.random() < 0.5 ? 'A' : 'B'
  }
  
  const response = Response.json({
    variant,
    config: {
      buttonColor: variant === 'A' ? 'blue' : 'green',
      headline: variant === 'A' ? 'Original Headline' : 'Test Headline'
    }
  })
  
  // Set cookie if not exists
  if (!existingVariant) {
    response.headers.set(
      'Set-Cookie',
      `ab_test=${variant}; Path=/; Max-Age=86400; SameSite=Strict`
    )
  }
  
  return response
}

This approach assigns users to test variants at the edge, ensuring consistent experiences across page loads while minimizing latency.

Step 4: Implement Rate Limiting

Edge Runtime can implement basic rate limiting using headers and simple logic:

// app/api/rate-limited/route.js
export const runtime = 'edge'

// Simple in-memory store (resets on function restart)
const requestCounts = new Map()

export async function POST(request) {
  const ip = request.headers.get('x-forwarded-for') || 'unknown'
  const now = Date.now()
  const windowMs = 60000 // 1 minute
  const maxRequests = 10
  
  // Clean old entries
  const cutoff = now - windowMs
  for (const [key, data] of requestCounts) {
    if (data.resetTime < cutoff) {
      requestCounts.delete(key)
    }
  }
  
  // Check current count
  const current = requestCounts.get(ip) || { count: 0, resetTime: now + windowMs }
  
  if (current.count >= maxRequests) {
    return Response.json(
      { error: 'Rate limit exceeded', retryAfter: current.resetTime - now },
      { status: 429 }
    )
  }
  
  // Increment counter
  requestCounts.set(ip, {
    count: current.count + 1,
    resetTime: current.resetTime
  })
  
  // Process the actual request
  const body = await request.json()
  
  return Response.json({
    success: true,
    data: body,
    remaining: maxRequests - current.count - 1
  })
}

This basic rate limiting works for many use cases, though production applications might need more sophisticated approaches using external stores.

Step 5: Migrate from Node.js Runtime

Migrating existing Node.js API routes requires adapting to Web APIs and removing Node.js dependencies:

// Before (Node.js runtime)
export default function handler(req, res) {
  if (req.method !== 'GET') {
    return res.status(405).json({ error: 'Method not allowed' })
  }
  
  const userAgent = req.headers['user-agent']
  
  res.status(200).json({
    userAgent,
    timestamp: new Date().toISOString()
  })
}

// After (Edge runtime)
export const runtime = 'edge'

export async function GET(request) {
  const userAgent = request.headers.get('user-agent')
  
  return Response.json({
    userAgent,
    timestamp: new Date().toISOString()
  })
}

The main changes involve switching from Express-style objects to Web API standards and ensuring all dependencies work in the Edge Runtime environment.

Common Mistakes and Troubleshooting

Avoid importing Node.js modules in Edge Runtime routes. Packages like fs, crypto (Node.js version), or database drivers that depend on Node.js internals will cause deployment failures. Use Web Crypto API instead of Node.js crypto, and prefer HTTP-based database connections over native drivers.

Edge functions have memory and execution time limits. Keep processing lightweight and avoid heavy computations or large data transformations. If you need complex processing, consider using Edge Runtime for routing decisions and Node.js runtime for heavy lifting.

Remember that Edge Runtime doesn't persist data between invocations reliably. The in-memory rate limiting example above works for demonstration but may reset unpredictably in production. Use external stores like Redis or database-backed solutions for persistent state.

Performance Testing Your Edge Routes

Test your Edge Runtime routes from multiple geographic locations to verify the performance benefits. Tools like Vercel's built-in analytics or external services can help measure actual response times across regions.

Monitor cold start times and memory usage through Vercel's dashboard. Edge functions should consistently start faster than Node.js equivalents, especially during traffic spikes.

Next Steps

Start by identifying API routes in your application that handle simple, latency-sensitive operations. Good candidates include authentication checks, feature flags, geolocation services, and request filtering.

Consider combining Edge Runtime with traditional Node.js routes in the same application. Use Edge Runtime for fast, simple operations and Node.js runtime for complex business logic that requires full library access.

For production applications, implement proper monitoring and error handling. Edge functions should gracefully degrade when external services are unavailable, ensuring your application remains responsive even when dependencies fail.

Ready to build something great?

Let's talk about your project. I offer 1-week MVP sprints, fractional CTO services, and Claude Code consulting.

View All Services