Security Headers on Vercel — Complete vercel.json Configuration
Updated April 2026
headers array with a source: "/(.*)" entry and list each header as key-value pairs. The headers apply to every deployment automatically. For Next.js, use the async headers() function in next.config.js instead.
Vercel sets security headers via vercel.json. No server config needed — just add a headers array and every deployment gets them automatically.
Complete vercel.json — copy and paste
{ "headers": [ { "source": "/(.*)", "headers": [ { "key": "Strict-Transport-Security", "value": "max-age=31536000; includeSubDomains" }, { "key": "X-Frame-Options", "value": "SAMEORIGIN" }, { "key": "X-Content-Type-Options", "value": "nosniff" }, { "key": "Referrer-Policy", "value": "strict-origin-when-cross-origin" }, { "key": "Permissions-Policy", "value": "camera=(), microphone=(), geolocation=(), interest-cohort=()" }, { "key": "Cross-Origin-Opener-Policy", "value": "same-origin" } ] } ]
}
Place this in vercel.json at the root of your project. Redeploy and headers will appear on every response.
Adding CSP
vercel.json Strict-Transport-Security example
The most searched vercel.json security header — exact copy-paste:
{ "headers": [ { "source": "/(.*)", "headers": [ { "key": "Strict-Transport-Security", "value": "max-age=31536000; includeSubDomains" } ] } ]
}
Add ; preload to the value only after verifying all subdomains support HTTPS and you've submitted at hstspreload.org.
CSP requires knowing your sources first. Add it as another entry in the headers array:
{ "key": "Content-Security-Policy", "value": "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self'; frame-ancestors 'none'; object-src 'none'; base-uri 'self';"
}
Content-Security-Policy-Report-Only instead of Content-Security-Policy — it logs violations without blocking anything. Switch to enforcing once violations stop appearing in the browser console.Path-specific headers
Apply different headers to different paths using separate source patterns:
{ "headers": [ { "source": "/(.*)", "headers": [ {"key": "X-Content-Type-Options", "value": "nosniff"}, {"key": "X-Frame-Options", "value": "SAMEORIGIN"} ] }, { "source": "/api/(.*)", "headers": [ {"key": "Cache-Control", "value": "no-store"}, {"key": "Access-Control-Allow-Origin", "value": "https://your-frontend.com"} ] }, { "source": "/static/(.*)", "headers": [ {"key": "Cache-Control", "value": "public, max-age=31536000, immutable"} ] } ]
}
Next.js — headers in next.config.js
For Next.js projects, you can set headers in next.config.js instead:
/** @type {import('next').NextConfig} */
const nextConfig = { async headers() { return [ { source: '/(.*)', headers: [ { key: 'X-Frame-Options', value: 'SAMEORIGIN' }, { key: 'X-Content-Type-Options', value: 'nosniff' }, { key: 'Referrer-Policy', value: 'strict-origin-when-cross-origin' }, { key: 'Strict-Transport-Security', value: 'max-age=31536000; includeSubDomains' }, { key: 'Permissions-Policy', value: 'camera=(), microphone=(), geolocation=()' }, ], }, ] },
}
module.exports = nextConfig
Vercel Edge Middleware
For dynamic header logic (e.g. different CSP per route), use Edge Middleware:
// middleware.ts
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'
export function middleware(request: NextRequest) { const response = NextResponse.next() response.headers.set('X-Frame-Options', 'SAMEORIGIN') response.headers.set('X-Content-Type-Options', 'nosniff') return response
}
export const config = { matcher: '/(.*)',
}
Verifying your headers
After deploying, paste your Vercel URL into HeadersFixer to confirm all headers are present and correctly configured:
Verify headers on your live site → HeadersFixer