Editor’s note: This article was last updated by Muhammed Ali on 19 June 2024 to cover the latest functions in Next.js for managing CORS, such as the use of crossOrigin
and the nextjs-cors package, and to incorporate the use of cross-origin-opener-policy
in React, as well as the strict-origin-when-cross-origin
configuration.
Over the past few years, Next.js has become a go-to framework not only for frontend development but also for API development. When building APIs, it is critical to spend some time on Cross-Origin Resource Sharing (CORS).
In this complete guide, you will explore several methods for using CORS in Next.js, enabling you to handle cross-origin requests effectively and securely.
CORS is a security mechanism that enables a server to specify which origins are allowed to access and load resources in a web browser. In this context, an “origin” refers to the combination of the protocol, domain, and port number a request comes from.
In detail, CORS is a protection system implemented by web browsers to enforce restrictions on cross-origin requests. Its main goal is to protect user security and prevent unauthorized access to resources and data.
To enforce CORS, browsers and servers exchange a set of specific HTTP headers. Before making certain types of cross-origin requests, the browser sends a preflight request using the HTTP OPTIONS
method to the server. The server then responds with some CORS headers, indicating whether the cross-origin should be permitted or denied.
If the preflight request is successful, the actual cross-origin request is performed by the browser. Otherwise, it gets blocked because of a CORS policy error.
The main CORS headers include:
Access-Control-Allow-Origin
: Specifies the origin that has access to the resourceAccess-Control-Allow-Methods
: Added to the preflight response to indicate the permitted HTTP methods, such as GET
, POST
, PUT
, etc.Access-Control-Allow-Headers
: Returned in response to a preflight request to specify the HTTP headers that are allowed in the current requestAccess-Control-Allow-Credentials
: Indicates whether the browser should include credentials, such as cookies or HTTP authentication, in the cross-origin requestCORS allows frontend applications to access resources from a different domain, ensuring secure cross-origin communication. By default, Next.js relies on a same-origin approach, imposing a strict policy. If you want to change that, you must configure it manually.
Next.js has supported API development since v9.4. As mentioned earlier, APIs in Next.js do not involve CORS headers by default, following a same-origin policy instead. This means they can only be accessed in the browser by pages within the same domain.
However, there are scenarios where you may want to access those endpoints from other origins. For example, if you had an application hosted on a different domain that needed to access those APIs in the frontend, it would be blocked by those cross-origin restrictions.
To avoid that issue, you need to enable CORS by configuring the appropriate headers on the Next.js server. This way, you can explicitly allow cross-origin requests for specific origins. Applications hosted on the trusted domains will then be able to make requests to your Next.js API routes.
Let’s now learn how to configure CORS in Next.js!
Before moving to the next section, be sure to meet the prerequisites below:
To follow this tutorial, it does not matter if your project is based on the Pages Router or the App Router; the proposed solutions will work in both scenarios.
From now on, we will assume that all API routes in your Next.js project are under the /api
path.
The most common approach to CORS is to set it up globally on all API endpoints. There are many ways to achieve that in Next.js. Here, you will explore three methods for using CORS in Next.js.
headers
configYou can manually set the CORS headers in Next.js thanks to the headers
key in next.config.js
:
// next.config.js /** @type {import('next').NextConfig} */ const nextConfig = { async headers() { return [ { // matching all API routes source: "/api/:path*", headers: [ { key: "Access-Control-Allow-Credentials", value: "true" }, { key: "Access-Control-Allow-Origin", value: "*" }, // replace this your actual origin { key: "Access-Control-Allow-Methods", value: "GET,DELETE,PATCH,POST,PUT" }, { key: "Access-Control-Allow-Headers", value: "X-CSRF-Token, X-Requested-With, Accept, Accept-Version, Content-Length, Content-MD5, Content-Type, Date, X-Api-Version" }, ] } ] } } module.exports = nextConfig
headers()
is an async
function that must return an array of objects. When the incoming request matches the source
path regex, the server will produce a response containing the custom HTTP headers
.
Note that the source
must follow a specific syntax. If an incorrect path regex is used, Next.js will throw an Invalid header found
error and fail with a `source` parse failed message
.
Next.js middleware enables you to perform specific operations before a request is completed. This also includes setting the CORS HTTP headers in the response. Based on your project structure, initialize a middleware.js
file inside the pages
, app
, or src
folder as shown below:
// src/middleware.js // or // src/app/middleware.js // or // src/pages/middleware.js import { NextResponse } from "next/server"; export function middleware() { // retrieve the current response const res = NextResponse.next() // add the CORS headers to the response res.headers.append('Access-Control-Allow-Credentials', "true") res.headers.append('Access-Control-Allow-Origin', '*') // replace this your actual origin res.headers.append('Access-Control-Allow-Methods', 'GET,DELETE,PATCH,POST,PUT') res.headers.append( 'Access-Control-Allow-Headers', 'X-CSRF-Token, X-Requested-With, Accept, Accept-Version, Content-Length, Content-MD5, Content-Type, Date, X-Api-Version' ) return res } // specify the path regex to apply the middleware to export const config = { matcher: '/api/:path*', }
Make sure to adapt the CORS policy specified in this snippet to your needs.
Note that the matcher
config accepts a regex path, forcing the middleware to run only on specific paths. If an incorrect value is used, Next.js will fail and display an Invalid middleware found
error message.
If your app relies on the App Router, you can remove the config
export and place this file directly in the src/app/api
path. In both cases, the middleware function will be applied to all API endpoints under the /api
path.
Chances are good that your Next.js project is hosted on Vercel, as Vercel is the development team behind Next.js. You can configure the CORS headers in a Next.js app deployed on Vercel by initializing a vercel.json
file in the root folder of your project like so:
{ "headers": [ { "source": "/api/(.*)", "headers": [ { "key": "Access-Control-Allow-Credentials", "value": "true" }, { "key": "Access-Control-Allow-Origin", "value": "*" }, { "key": "Access-Control-Allow-Methods", "value": "GET,DELETE,PATCH,POST,PUT" }, { "key": "Access-Control-Allow-Headers", "value": "X-CSRF-Token, X-Requested-With, Accept, Accept-Version, Content-Length, Content-MD5, Content-Type, Date, X-Api-Version" } ] } ] }
As you can see, the headers
key has a similar syntax to the equivalent one in next.config.js
. What changes is the format of the source
field.
Alternatively, you can also set up CORS with the following Vercel serverless function:
const enableCors = fn => async (req, res) => { res.setHeader('Access-Control-Allow-Credentials', true) res.setHeader('Access-Control-Allow-Origin', '*') // replace this your actual origin res.setHeader('Access-Control-Allow-Methods', 'GET,DELETE,PATCH,POST,PUT') res.setHeader( 'Access-Control-Allow-Headers', 'X-CSRF-Token, X-Requested-With, Accept, Accept-Version, Content-Length, Content-MD5, Content-Type, Date, X-Api-Version' ) // specific logic for the preflight request if (req.method === 'OPTIONS') { res.status(200).end() return } return await fn(req, res) } const handler = (req, res) => { const currentDate = new Date() res.end(currentDate.toString()) } module.exports = enableCors(handler)
Et voilĂ ! You now know how to use CORS on all your Next.js API endpoints!
Now that we have covered the basics for enabling CORS in Next.js, let’s explore some advanced cross-origin policies that can further enhance your security setup.
Cross-Origin-Opener-Policy
in ReactThe Cross-Origin-Opener-Policy
(COOP) header is used to secure your site by isolating browsing contexts like a tab or window. This prevents a webpage from sharing a browsing context with cross-origin documents. This can be useful in protecting your site from attacks like cross-site scripting (XSS) and data stolen through shared browsing contexts.
To set this header in a Next.js application, you can add it to the headers
section of your next.config.js
:
// next.config.js /** @type {import('next').NextConfig} */ const nextConfig = { async headers() { return [ { // matching all API routes source: "/api/:path*", headers: [ // other headers omitted for brevity... { key: "Cross-Origin-Opener-Policy", value: "same-origin" } ] } ] } } module.exports = nextConfig
Strict-Origin-When-Cross-Origin
configurationThe Strict-Origin-When-Cross-Origin
policy provides more privacy and security when compared to policies like no-referrer-when-downgrade
. This is done by sending the full URL only when the origin of the request matches the origin of the resource. For cross-origin requests, only the origin is sent.
To set this header in your Next.js application, include it in your headers
section:
// next.config.js /** @type {import('next').NextConfig} */ const nextConfig = { async headers() { return [ { // matching all API routes source: "/api/:path*", headers: [ // other headers omitted for brevity... { key: "Referrer-Policy", value: "strict-origin-when-cross-origin" } ] } ] } } module.exports = nextConfig
Now, assume your frontend app needs to perform a GET
API call to /api/hello-world
. This is what the preflight request will look like:
By the 2xx
HTTP status code, you can tell that the preflight request was performed successfully. The browser is now allowed to execute the actual cross-origin request:
Focus on the CORS headers in the Response Headers section. They match the ones defined in the approaches above.
Before wrapping up, here are some CORS Next.js tips and tricks you should know.
ALLOW
header values from the env variablesCORS policies may change over time. Thus, you should not hardcode them. Instead, you can set up some environment variables as shown below:
ACCESS_CONTROL_ALLOW_CREDENTIALS="true" ACCESS_CONTROL_ALLOW_ORIGIN="*" ACCESS_CONTROL_ALLOW_METHODS="GET,OPTIONS,PATCH,DELETE,POST,PUT" ACCESS_CONTROL_ALLOW_HEADERS="X-CSRF-Token, X-Requested-With, Accept, Accept-Version, Content-Length, Content-MD5, Content-Type, Date, X-Api-Version"
Then, use them in your code:
res.headers.append('Access-Control-Allow-Credentials', process.env.ACCESS_CONTROL_ALLOW_CREDENTIALS) res.headers.append('Access-Control-Allow-Origin', process.env.ACCESS_CONTROL_ALLOW_ORIGIN) // replace this your actual origin res.headers.append('Access-Control-Allow-Methods', process.env.ACCESS_CONTROL_ALLOW_METHODS) res.headers.append('Access-Control-Allow-Headers', process.env.ACCESS_CONTROL_ALLOW_HEADERS)
Great! The CORS definition logic no longer involves hardcoded strings.
The Access-Control-Allow-Origin
header is a binary option that accepts either a single origin or all origins. You would use an asterisk *
to set this header to accept all domains, but this wildcard cannot be used when credentials are included in the request.
If you want to permit multiple but not all CORS origins, you need to write custom logic. Keep in mind that you can only implement this approach with the middleware solution. The other two options for enabling CORS in Next.js involve static files that do not accept custom behavior.
Update the middleware.js
file as shown below:
import { NextResponse } from "next/server"; // the list of all allowed origins const allowedOrigins = [ 'http://localhost:3000', 'https://example-1.com', 'https://example-2.com', // ... 'https://example-99.com', ]; export function middleware(req) { // retrieve the current response const res = NextResponse.next() // retrieve the HTTP "Origin" header // from the incoming request req.headers.get("origin") // if the origin is an allowed one, // add it to the 'Access-Control-Allow-Origin' header if (allowedOrigins.includes(origin)) { res.headers.append('Access-Control-Allow-Origin', origin); } // add the remaining CORS headers to the response res.headers.append('Access-Control-Allow-Credentials', "true") res.headers.append('Access-Control-Allow-Methods', 'GET,DELETE,PATCH,POST,PUT') res.headers.append( 'Access-Control-Allow-Headers', 'X-CSRF-Token, X-Requested-With, Accept, Accept-Version, Content-Length, Content-MD5, Content-Type, Date, X-Api-Version' ) return res } // specify the path regex to apply the middleware to export const config = { matcher: '/api/:path*', }
Basically, all you have to do is check whether the current Origin
header sent by the browser matches one of those allowed. If so, specify the Origin
variable in the appropriate CORS header to enable cross-origin requests from it.
Suppose you want to define a particular CORS policy for the /api/special-data
endpoint. To do so, you could add a new entry to the array returned by headers()
in next.config.js
:
// next.config.js /** @type {import('next').NextConfig} */ const nextConfig = { async headers() { return [ { // matching all API routes source: "/api/:path*", headers: [ // omitted for brevity... ] }, { source: "/api/special-data", headers: [ { key: "Access-Control-Allow-Credentials", value: "false" }, { key: "Access-Control-Allow-Origin", value: "https://example.com" }, { key: "Access-Control-Allow-Methods", value: "GET,DELETE,PATCH,POST,PUT" }, { key: "Access-Control-Allow-Headers", value: "Accept, Accept-Version, Content-Length, Content-MD5, Content-Type, Date" }, ] } ] } } module.exports = nextConfig
Note that the source
field of the second entry matches the endpoint of the desired API. This means that Next.js will prefer it to the more generic first entry.
Otherwise, you could update middleware.js
and adapt its logic based on the request’s pathname:
import { NextResponse } from "next/server"; export function middleware(req) { // retrieve the current response const res = NextResponse.next() // if the incoming is for the desired API endpoint if (req.nextUrl.pathname === '/special-data') { res.headers.append('Access-Control-Allow-Credentials', "false") res.headers.append('Access-Control-Allow-Origin', 'https://example.com') res.headers.append('Access-Control-Allow-Methods', 'GET,DELETE,PATCH,POST,PUT') res.headers.append('Access-Control-Allow-Headers', 'Accept, Accept-Version, Content-Length, Content-MD5, Content-Type, Date') } else { // generic CORS policy omitted for brevity.... } return res } // specify the path regex to apply the middleware to export const config = { matcher: '/api/:path*', }
If you are an App Router user, you can get the same result by creating a middleware.js
file in the src/app/special-data
folder.
Fantastic! The single-origin restriction is no longer an issue!
Next.js has recently introduced several new features to make managing CORS easier.
crossOrigin
The crossOrigin
configuration option allows you to specify how the resource should be fetched with a CORS request:
// next.config.js /** @type {import('next').NextConfig} */ const nextConfig = { crossOrigin: 'anonymous', // or 'use-credentials' // other configurations... } module.exports = nextConfig
The nextjs-cors package provides middleware to enable CORS in Next.js applications easily. First, install the package:
npm install nextjs-cors
Then, use it in your API routes like so:
import NextCors from 'nextjs-cors'; export default async function handler(req, res) { await NextCors(req, res, { // Options methods: ['GET', 'HEAD', 'PUT', 'PATCH', 'POST', 'DELETE'], origin: '*', // replace this with your actual origin optionsSuccessStatus: 200, // some legacy browsers (IE11, various SmartTVs) choke on 204 }); res.json({ message: 'Hello Next.js!' }); }
In this guide, we learned what CORS is and its significance for enhancing the security of backend applications. More specifically, we took a look at the most critical CORS headers and how to configure them in Next.js.
There are several ways to deal with CORS in Next.js. These configurations require minimal code but provide substantial security benefits.
Thanks to the Next.js capabilities, configuring CORS has never been easier. Make your site more secure today.
Debugging Next applications can be difficult, especially when users experience issues that are difficult to reproduce. If you’re interested in monitoring and tracking state, automatically surfacing JavaScript errors, and tracking slow network requests and component load time, try LogRocket.
LogRocket is like a DVR for web and mobile apps, recording literally everything that happens on your Next.js app. Instead of guessing why problems happen, you can aggregate and report on what state your application was in when an issue occurred. LogRocket also monitors your app's performance, reporting with metrics like client CPU load, client memory usage, and more.
The LogRocket Redux middleware package adds an extra layer of visibility into your user sessions. LogRocket logs all actions and state from your Redux stores.
Modernize how you debug your Next.js apps — start monitoring for free.
Hey there, want to help make our blog better?
Join LogRocket’s Content Advisory Board. You’ll help inform the type of content we create and get access to exclusive meetups, social accreditation, and swag.
Sign up nowEfficient initializing is crucial to smooth-running websites. One way to optimize that process is through lazy initialization in Rust 1.80.
Design React Native UIs that look great on any device by using adaptive layouts, responsive scaling, and platform-specific tools.
Angular’s two-way data binding has evolved with signals, offering improved performance, simpler syntax, and better type inference.
Fix sticky positioning issues in CSS, from missing offsets to overflow conflicts in flex, grid, and container height constraints.
2 Replies to "Using CORS in Next.js to handle cross-origin requests"
Hi, thanks for this. src/app/middleware.ts didn’t work for me but src/middleware.ts did.
nice it works I have done it in src/middleware.ts