diff --git a/docs/02-app/01-building-your-application/01-routing/12-route-handlers.mdx b/docs/02-app/01-building-your-application/01-routing/12-route-handlers.mdx
index 450a873dcdbed..122a4c620e8de 100644
--- a/docs/02-app/01-building-your-application/01-routing/12-route-handlers.mdx
+++ b/docs/02-app/01-building-your-application/01-routing/12-route-handlers.mdx
@@ -572,7 +572,7 @@ Since `formData` data are all strings, you may want to use [`zod-form-data`](htt
### CORS
-You can set CORS headers on a `Response` using the standard Web API methods:
+You can set CORS headers for a specific Route Handler using the standard Web API methods:
```ts filename="app/api/route.ts" switcher
export const dynamic = 'force-dynamic' // defaults to auto
@@ -604,6 +604,11 @@ export async function GET(request) {
}
```
+> **Good to know**:
+>
+> - To add CORS headers to multiple Route Handlers, you can use [Middleware](/docs/app/building-your-application/routing/middleware#cors) or the [`next.config.js` file](/docs/app/api-reference/next-config-js/headers#cors).
+> - Alternatively, see our [CORS example](https://github.com/vercel/examples/blob/main/edge-functions/cors/lib/cors.ts) package.
+
### Webhooks
You can use a Route Handler to receive webhooks from third-party services:
diff --git a/docs/02-app/01-building-your-application/01-routing/13-middleware.mdx b/docs/02-app/01-building-your-application/01-routing/13-middleware.mdx
index 2625c25101390..2091aec5a3e03 100644
--- a/docs/02-app/01-building-your-application/01-routing/13-middleware.mdx
+++ b/docs/02-app/01-building-your-application/01-routing/13-middleware.mdx
@@ -313,6 +313,106 @@ export function middleware(request) {
> **Good to know**: Avoid setting large headers as it might cause [431 Request Header Fields Too Large](https://developer.mozilla.org/docs/Web/HTTP/Status/431) error depending on your backend web server configuration.
+### CORS
+
+You can set CORS headers in Middleware to allow cross-origin requests, including [simple](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#simple_requests) and [preflighted](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#preflighted_requests) requests.
+
+```tsx filename="middleware.ts" switcher
+import { NextRequest, NextResponse } from 'next/server'
+
+const allowedOrigins = ['https://acme.com', 'https://my-app.org']
+
+const corsOptions = {
+ 'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS',
+ 'Access-Control-Allow-Headers': 'Content-Type, Authorization',
+}
+
+export function middleware(request: NextRequest) {
+ // Check the origin from the request
+ const origin = request.headers.get('origin') ?? ''
+ const isAllowedOrigin = allowedOrigins.includes(origin)
+
+ // Handle preflighted requests
+ const isPreflight = request.method === 'OPTIONS'
+
+ if (isPreflight) {
+ const preflightHeaders = {
+ ...(isAllowedOrigin && { 'Access-Control-Allow-Origin': origin }),
+ ...corsOptions,
+ }
+ return NextResponse.json({}, { headers: preflightHeaders })
+ }
+
+ // Handle simple requests
+ const response = NextResponse.next()
+
+ if (isAllowedOrigin) {
+ response.headers.set('Access-Control-Allow-Origin', origin)
+ }
+
+ Object.entries(corsOptions).forEach(([key, value]) => {
+ response.headers.set(key, value)
+ })
+
+ return response
+}
+
+export const config = {
+ matcher: '/api/:path*',
+}
+```
+
+```jsx filename="middleware.js" switcher
+import { NextResponse } from 'next/server'
+
+const allowedOrigins = ['https://acme.com', 'https://my-app.org']
+
+const corsOptions = {
+ 'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS',
+ 'Access-Control-Allow-Headers': 'Content-Type, Authorization',
+}
+
+export function middleware(request) {
+ // Check the origin from the request
+ const origin = request.headers.get('origin') ?? ''
+ const isAllowedOrigin = allowedOrigins.includes(origin)
+
+ // Handle preflighted requests
+ const isPreflight = request.method === 'OPTIONS'
+
+ if (isPreflight) {
+ const preflightHeaders = {
+ ...(isAllowedOrigin && { 'Access-Control-Allow-Origin': origin }),
+ ...corsOptions,
+ }
+ return NextResponse.json({}, { headers: preflightHeaders })
+ }
+
+ // Handle simple requests
+ const response = NextResponse.next()
+
+ if (isAllowedOrigin) {
+ response.headers.set('Access-Control-Allow-Origin', origin)
+ }
+
+ Object.entries(corsOptions).forEach(([key, value]) => {
+ response.headers.set(key, value)
+ })
+
+ return response
+}
+
+export const config = {
+ matcher: '/api/:path*',
+}
+```
+
+
+
+> **Good to know:** You can configure CORS headers for individual routes in [Route Handlers](/docs/app/building-your-application/routing/route-handlers#cors).
+
+
+
## Producing a Response
You can respond from Middleware directly by returning a `Response` or `NextResponse` instance. (This is available since [Next.js v13.1.0](https://nextjs.org/blog/next-13-1#nextjs-advanced-middleware))
diff --git a/docs/02-app/02-api-reference/05-next-config-js/headers.mdx b/docs/02-app/02-api-reference/05-next-config-js/headers.mdx
index 0576571667889..d8ed4ee398311 100644
--- a/docs/02-app/02-api-reference/05-next-config-js/headers.mdx
+++ b/docs/02-app/02-api-reference/05-next-config-js/headers.mdx
@@ -429,6 +429,34 @@ export default function handler(req, res) {
## Options
+### CORS
+
+[Cross-Origin Resource Sharing (CORS)](https://developer.mozilla.org/docs/Web/HTTP/CORS) is a security feature that allows you to control which sites can access your resources. You can set the `Access-Control-Allow-Origin` header to allow a specific origin to access your API EndpointsRoute Handlers.
+
+```js
+async headers() {
+ return [
+ {
+ source: "/api/:path*",
+ headers: [
+ {
+ key: "Access-Control-Allow-Origin",
+ value: "*", // Set your origin
+ },
+ {
+ key: "Access-Control-Allow-Methods",
+ value: "GET, POST, PUT, DELETE, OPTIONS",
+ },
+ {
+ key: "Access-Control-Allow-Headers",
+ value: "Content-Type, Authorization",
+ },
+ ],
+ },
+ ];
+ },
+```
+
### X-DNS-Prefetch-Control
[This header](https://developer.mozilla.org/docs/Web/HTTP/Headers/X-DNS-Prefetch-Control) controls DNS prefetching, allowing browsers to proactively perform domain name resolution on external links, images, CSS, JavaScript, and more. This prefetching is performed in the background, so the [DNS](https://developer.mozilla.org/docs/Glossary/DNS) is more likely to be resolved by the time the referenced items are needed. This reduces latency when the user clicks a link.