Skip to content

Next.js API Route CORS Error Fix

DodaTech Updated 2026-06-24 3 min read

In this tutorial, you'll learn about Next.js API Route CORS Error Fix. We cover key concepts, practical examples, and best practices.

The Problem

Browser requests to a Next.js API route fail with CORS Missing Allow Origin or CORS Preflight Did Not Succeed. Next.js API routes do not include CORS headers by default.

Quick Fix

Step 1: Add CORS headers to the API response

// Wrong — no CORS headers
export default function handler(req, res) {
    res.status(200).json({ message: 'OK' });
}

// Right
export default function handler(req, res) {
    res.setHeader('Access-Control-Allow-Origin', '*');
    res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
    res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization');
    res.status(200).json({ message: 'OK' });
}

Expected output: The browser accepts the response from any origin.

Step 2: Handle OPTIONS preflight requests

export default function handler(req, res) {
    // Handle CORS preflight
    if (req.method === 'OPTIONS') {
        res.setHeader('Access-Control-Allow-Origin', '*');
        res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
        res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization');
        return res.status(200).end();
    }

    // Handle actual request
    res.setHeader('Access-Control-Allow-Origin', '*');
    res.status(200).json({ message: 'OK' });
}

Expected output: The preflight OPTIONS request returns 200 with CORS headers.

Step 3: Use a CORS middleware

// lib/cors.js
export function cors(req, res) {
    const origin = req.headers.origin;
    const allowedOrigins = [
        'https://example.com',
        'http://localhost:3000',
    ];

    if (allowedOrigins.includes(origin)) {
        res.setHeader('Access-Control-Allow-Origin', origin);
    }

    res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
    res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization');
}

// pages/api/hello.js
import { cors } from '@/lib/cors';

export default function handler(req, res) {
    cors(req, res);

    if (req.method === 'OPTIONS') {
        return res.status(200).end();
    }

    res.status(200).json({ message: 'OK' });
}

Expected output: CORS headers are set consistently across all API routes.

Step 4: Use environment-specific origins

export function cors(req, res) {
    const allowedOrigins = process.env.CORS_ORIGINS
        ? process.env.CORS_ORIGINS.split(',')
        : ['http://localhost:3000'];

    const origin = req.headers.origin;
    if (allowedOrigins.includes(origin) || allowedOrigins.includes('*')) {
        res.setHeader('Access-Control-Allow-Origin', origin);
    }
}

Expected output: Allowed origins are configurable per environment.

Step 5: Apply CORS to all API routes with a wrapper

// lib/withCors.js
export function withCors(handler) {
    return (req, res) => {
        res.setHeader('Access-Control-Allow-Origin', '*');
        res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');

        if (req.method === 'OPTIONS') {
            return res.status(200).end();
        }

        return handler(req, res);
    };
}

// pages/api/hello.js
export default withCors(function handler(req, res) {
    res.status(200).json({ message: 'OK' });
});

Expected output: Every wrapped API route includes CORS headers automatically.

Prevention

  • Add CORS headers to all API routes that are called from different origins
  • Handle OPTIONS preflight requests explicitly
  • Restrict Access-Control-Allow-Origin to specific domains in production
  • Use a middleware pattern to avoid duplicating CORS logic

Common Mistakes with api cors

  1. Using return to exit a function early instead of wrapping a pure value in the monad
  2. Mixing let bindings with <- bindings in do notation, producing type errors
  3. Overlapping type class instances that cause GHC to reject the program with ambiguous dispatch errors

These mistakes appear frequently in real-world NEXTJS code. DodaTech's contributors have identified these patterns through analysis of open-source projects and production systems.

Practice Exercise

Write a pure function that safely divides two integers using Maybe, then test it with edge cases like division by zero and negative numbers.

This exercise reinforces the concepts covered in this guide. Try implementing it before checking online solutions.

FAQ

### Why does my API route work in Postman but fail in the browser?

Postman does not enforce CORS. Browsers block cross-origin responses without proper CORS headers. If the API route works in Postman but fails in the browser, check the Access-Control-Allow-Origin header in the response.

What is a CORS preflight request?

A preflight is an OPTIONS request the browser sends before the actual request when certain conditions are met (non-simple methods, custom headers, or credentials). The server must respond with CORS headers for the browser to proceed with the actual request.

Should I set Access-Control-Allow-Origin to * in production?

Avoid * in production if your API handles authenticated requests or sensitive data. Use specific origins instead. The * wildcard prevents the browser from sending credentials (cookies, Authorization headers). For credentialed requests, list specific origins explicitly.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro