[{"data":1,"prerenderedAt":451},["ShallowReactive",2],{"blog-best-practices/vercel":3},{"id":4,"title":5,"body":6,"category":425,"date":426,"dateModified":427,"description":428,"draft":429,"extension":430,"faq":431,"featured":429,"headerVariant":436,"image":437,"keywords":437,"meta":438,"navigation":439,"ogDescription":440,"ogTitle":437,"path":441,"readTime":442,"schemaOrg":443,"schemaType":444,"seo":445,"sitemap":446,"stem":447,"tags":448,"twitterCard":449,"__hash__":450},"blog/blog/best-practices/vercel.md","Vercel Security Best Practices: Headers, Env Vars, and Deployment",{"type":7,"value":8,"toc":407},"minimark",[9,20,29,34,37,52,57,60,69,73,76,121,130,139,143,146,150,166,170,173,182,186,189,198,202,205,214,218,221,230,234,237,264,269,292,321,349,353,356,376,395],[10,11,12],"tldr",{},[13,14,15,19],"p",{},[16,17,18],"strong",{},"The #1 Vercel security best practice is configuring security headers in vercel.json."," These 7 practices take about 55 minutes to implement and address 81% of security issues found in Vercel deployments. Focus on: adding security headers, keeping secrets out of NEXT_PUBLIC_ variables, protecting preview deployments, and using Edge Middleware for authentication.",[21,22,23],"quotable-box",{},[24,25,26],"blockquote",{},[13,27,28],{},"\"Vercel secures the infrastructure; you secure the application. Headers, environment variables, and middleware are your responsibility.\"",[30,31,33],"h2",{"id":32},"best-practice-1-add-security-headers-5-min","Best Practice 1: Add Security Headers 5 min",[13,35,36],{},"Security headers protect against common web attacks. Configure them in vercel.json:",[38,39,41],"code-block",{"label":40},"vercel.json with security headers",[42,43,48],"pre",{"className":44,"code":46,"language":47},[45],"language-text","{\n  \"headers\": [\n    {\n      \"source\": \"/(.*)\",\n      \"headers\": [\n        {\n          \"key\": \"X-Content-Type-Options\",\n          \"value\": \"nosniff\"\n        },\n        {\n          \"key\": \"X-Frame-Options\",\n          \"value\": \"DENY\"\n        },\n        {\n          \"key\": \"X-XSS-Protection\",\n          \"value\": \"1; mode=block\"\n        },\n        {\n          \"key\": \"Referrer-Policy\",\n          \"value\": \"strict-origin-when-cross-origin\"\n        },\n        {\n          \"key\": \"Permissions-Policy\",\n          \"value\": \"camera=(), microphone=(), geolocation=()\"\n        }\n      ]\n    }\n  ]\n}\n","text",[49,50,46],"code",{"__ignoreMap":51},"",[53,54,56],"h3",{"id":55},"content-security-policy","Content Security Policy",[13,58,59],{},"Add CSP for additional protection (customize based on your app's needs):",[38,61,63],{"label":62},"CSP header example",[42,64,67],{"className":65,"code":66,"language":47},[45],"{\n  \"key\": \"Content-Security-Policy\",\n  \"value\": \"default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' https://fonts.gstatic.com; connect-src 'self' https://api.yourdomain.com\"\n}\n",[49,68,66],{"__ignoreMap":51},[30,70,72],{"id":71},"best-practice-2-secure-environment-variables-3-min","Best Practice 2: Secure Environment Variables 3 min",[13,74,75],{},"Vercel has specific rules for environment variable exposure:",[77,78,79,95],"table",{},[80,81,82],"thead",{},[83,84,85,89,92],"tr",{},[86,87,88],"th",{},"Prefix",[86,90,91],{},"Exposed to Browser?",[86,93,94],{},"Use For",[96,97,98,110],"tbody",{},[83,99,100,104,107],{},[101,102,103],"td",{},"NEXT_PUBLIC_",[101,105,106],{},"Yes",[101,108,109],{},"Public API URLs, feature flags",[83,111,112,115,118],{},[101,113,114],{},"No prefix",[101,116,117],{},"No (server only)",[101,119,120],{},"API keys, secrets, credentials",[122,123,124],"warning-box",{},[13,125,126,129],{},[16,127,128],{},"Important:"," Any environment variable starting with NEXT_PUBLIC_ will be included in your client-side bundle and visible to users. Never put secrets in NEXT_PUBLIC_ variables.",[38,131,133],{"label":132},"Correct environment variable usage",[42,134,137],{"className":135,"code":136,"language":47},[45],"// Safe: Server-side only (no NEXT_PUBLIC_ prefix)\nconst stripeSecretKey = process.env.STRIPE_SECRET_KEY;\nconst databaseUrl = process.env.DATABASE_URL;\n\n// Safe: Intentionally public\nconst supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL;\nconst appUrl = process.env.NEXT_PUBLIC_APP_URL;\n\n// WRONG: Secret with public prefix\n// const apiSecret = process.env.NEXT_PUBLIC_API_SECRET; // Never do this!\n",[49,138,136],{"__ignoreMap":51},[30,140,142],{"id":141},"best-practice-3-protect-preview-deployments-2-min","Best Practice 3: Protect Preview Deployments 2 min",[13,144,145],{},"Preview deployments can expose unfinished features or test data. Protect them:",[53,147,149],{"id":148},"vercel-authentication","Vercel Authentication",[151,152,153,157,160,163],"ol",{},[154,155,156],"li",{},"Go to Project Settings in Vercel Dashboard",[154,158,159],{},"Navigate to Deployment Protection",[154,161,162],{},"Enable Vercel Authentication for Preview deployments",[154,164,165],{},"Configure which team members can access previews",[53,167,169],{"id":168},"password-protection","Password Protection",[13,171,172],{},"For additional protection, add password authentication to previews:",[38,174,176],{"label":175},"Deployment Protection settings",[42,177,180],{"className":178,"code":179,"language":47},[45],"// In Vercel Dashboard > Settings > Deployment Protection\n{\n  \"protection\": {\n    \"preview\": {\n      \"enabled\": true,\n      \"password\": true  // Requires password for access\n    }\n  }\n}\n",[49,181,179],{"__ignoreMap":51},[30,183,185],{"id":184},"best-practice-4-use-edge-middleware-for-auth-15-min","Best Practice 4: Use Edge Middleware for Auth 15 min",[13,187,188],{},"Protect routes at the edge before they reach your application:",[38,190,192],{"label":191},"middleware.ts",[42,193,196],{"className":194,"code":195,"language":47},[45],"import { NextResponse } from 'next/server';\nimport type { NextRequest } from 'next/server';\n\nexport function middleware(request: NextRequest) {\n  // Check for auth token\n  const token = request.cookies.get('auth-token');\n\n  // Protected routes\n  if (request.nextUrl.pathname.startsWith('/dashboard')) {\n    if (!token) {\n      return NextResponse.redirect(new URL('/login', request.url));\n    }\n  }\n\n  // Admin routes\n  if (request.nextUrl.pathname.startsWith('/admin')) {\n    if (!token) {\n      return NextResponse.redirect(new URL('/login', request.url));\n    }\n    // Additional admin check would go here\n  }\n\n  return NextResponse.next();\n}\n\nexport const config = {\n  matcher: ['/dashboard/:path*', '/admin/:path*', '/api/protected/:path*']\n};\n",[49,197,195],{"__ignoreMap":51},[30,199,201],{"id":200},"best-practice-5-secure-api-routes-15-min","Best Practice 5: Secure API Routes 15 min",[13,203,204],{},"Vercel API routes (or Next.js route handlers) need proper security:",[38,206,208],{"label":207},"Secure API route pattern",[42,209,212],{"className":210,"code":211,"language":47},[45],"// app/api/user/route.ts\nimport { NextRequest, NextResponse } from 'next/server';\nimport { verifyAuth } from '@/lib/auth';\n\nexport async function GET(request: NextRequest) {\n  // Verify authentication\n  const authResult = await verifyAuth(request);\n  if (!authResult.success) {\n    return NextResponse.json(\n      { error: 'Unauthorized' },\n      { status: 401 }\n    );\n  }\n\n  // Rate limiting check\n  const rateLimitResult = await checkRateLimit(authResult.userId);\n  if (!rateLimitResult.allowed) {\n    return NextResponse.json(\n      { error: 'Too many requests' },\n      { status: 429 }\n    );\n  }\n\n  // Proceed with authenticated request\n  const userData = await getUserData(authResult.userId);\n  return NextResponse.json(userData);\n}\n\nexport async function POST(request: NextRequest) {\n  const authResult = await verifyAuth(request);\n  if (!authResult.success) {\n    return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });\n  }\n\n  // Validate input\n  const body = await request.json();\n  const validation = validateUserUpdate(body);\n  if (!validation.success) {\n    return NextResponse.json(\n      { error: 'Invalid input', details: validation.errors },\n      { status: 400 }\n    );\n  }\n\n  // Process request...\n}\n",[49,213,211],{"__ignoreMap":51},[30,215,217],{"id":216},"best-practice-6-configure-cors-properly-10-min","Best Practice 6: Configure CORS Properly 10 min",[13,219,220],{},"For API routes that need CORS, configure it explicitly:",[38,222,224],{"label":223},"CORS configuration in API route",[42,225,228],{"className":226,"code":227,"language":47},[45],"// app/api/public/route.ts\nimport { NextRequest, NextResponse } from 'next/server';\n\nconst allowedOrigins = [\n  'https://yourdomain.com',\n  'https://app.yourdomain.com',\n];\n\nexport async function OPTIONS(request: NextRequest) {\n  const origin = request.headers.get('origin');\n\n  if (origin && allowedOrigins.includes(origin)) {\n    return new NextResponse(null, {\n      status: 204,\n      headers: {\n        'Access-Control-Allow-Origin': origin,\n        'Access-Control-Allow-Methods': 'GET, POST, OPTIONS',\n        'Access-Control-Allow-Headers': 'Content-Type, Authorization',\n        'Access-Control-Max-Age': '86400',\n      },\n    });\n  }\n\n  return new NextResponse(null, { status: 403 });\n}\n\nexport async function GET(request: NextRequest) {\n  const origin = request.headers.get('origin');\n  const response = NextResponse.json({ data: 'example' });\n\n  if (origin && allowedOrigins.includes(origin)) {\n    response.headers.set('Access-Control-Allow-Origin', origin);\n  }\n\n  return response;\n}\n",[49,229,227],{"__ignoreMap":51},[30,231,233],{"id":232},"best-practice-7-monitor-and-alert-5-min","Best Practice 7: Monitor and Alert 5 min",[13,235,236],{},"Set up monitoring for your Vercel deployment:",[238,239,240,246,252,258],"ul",{},[154,241,242,245],{},[16,243,244],{},"Vercel Analytics:"," Monitor performance and errors",[154,247,248,251],{},[16,249,250],{},"Log Drains:"," Send logs to external monitoring services",[154,253,254,257],{},[16,255,256],{},"Status Alerts:"," Get notified of deployment issues",[154,259,260,263],{},[16,261,262],{},"Speed Insights:"," Track Core Web Vitals",[265,266,268],"h4",{"id":267},"vercel-security-checklist","Vercel Security Checklist:",[238,270,271,274,277,280,283,286,289],{},[154,272,273],{},"Security headers configured in vercel.json",[154,275,276],{},"No secrets in NEXT_PUBLIC_ environment variables",[154,278,279],{},"Preview deployments protected with authentication",[154,281,282],{},"Edge Middleware protecting sensitive routes",[154,284,285],{},"API routes validate authentication and input",[154,287,288],{},"CORS configured with specific allowed origins",[154,290,291],{},"Monitoring and alerts enabled",[293,294,295],"info-box",{},[13,296,297,300,301,308,309,314,315,320],{},[16,298,299],{},"Official Resources:"," For the latest information, see ",[302,303,307],"a",{"href":304,"rel":305},"https://vercel.com/docs/security",[306],"nofollow","Vercel Security Documentation",", ",[302,310,313],{"href":311,"rel":312},"https://vercel.com/docs/edge-network/headers",[306],"Vercel Headers Configuration",", and ",[302,316,319],{"href":317,"rel":318},"https://vercel.com/docs/security/deployment-protection",[306],"Deployment Protection Guide",".",[322,323,324,331,337,343],"faq-section",{},[325,326,328],"faq-item",{"question":327},"Is Vercel secure by default?",[13,329,330],{},"Vercel provides a secure infrastructure with automatic HTTPS, DDoS protection, and isolated builds. However, application-level security like headers, environment variable handling, and authentication is your responsibility to configure.",[325,332,334],{"question":333},"How do I protect API routes on Vercel?",[13,335,336],{},"Use Edge Middleware for route-level protection, implement authentication checks in each API route, add rate limiting, and validate all input. Never trust client-side data without server-side validation.",[325,338,340],{"question":339},"Are environment variables safe on Vercel?",[13,341,342],{},"Server-side environment variables (without NEXT_PUBLIC_ prefix) are encrypted and only available during build and runtime on the server. Variables with NEXT_PUBLIC_ prefix are bundled into client code and visible to users.",[325,344,346],{"question":345},"Should I protect preview deployments?",[13,347,348],{},"Yes. Preview deployments can expose unfinished features, test data, or security vulnerabilities. Enable Vercel Authentication or password protection for all preview deployments, especially for production projects.",[30,350,352],{"id":351},"further-reading","Further Reading",[13,354,355],{},"Put these practices into action with our step-by-step guides.",[238,357,358,364,370],{},[154,359,360],{},[302,361,363],{"href":362},"/blog/how-to/add-security-headers","Add security headers to your app",[154,365,366],{},[302,367,369],{"href":368},"/blog/checklists/pre-deployment-security-checklist","Pre-deployment security checklist",[154,371,372],{},[302,373,375],{"href":374},"/blog/getting-started/first-scan","Run your first security scan",[377,378,379,385,390],"related-articles",{},[380,381],"related-card",{"description":382,"href":383,"title":384},"Complete security guide","/blog/guides/vercel","Vercel Security Guide",[380,386],{"description":387,"href":388,"title":389},"Pre-launch checklist","/blog/checklists/vercel-security-checklist","Vercel Checklist",[380,391],{"description":392,"href":393,"title":394},"Header configuration guide","/blog/best-practices/headers","Security Headers",[396,397,400,404],"cta-box",{"href":398,"label":399},"/","Start Free Scan",[30,401,403],{"id":402},"verify-your-vercel-security","Verify Your Vercel Security",[13,405,406],{},"Scan your Vercel deployment for security headers and configuration issues.",{"title":51,"searchDepth":408,"depth":408,"links":409},2,[410,414,415,419,420,421,422,423,424],{"id":32,"depth":408,"text":33,"children":411},[412],{"id":55,"depth":413,"text":56},3,{"id":71,"depth":408,"text":72},{"id":141,"depth":408,"text":142,"children":416},[417,418],{"id":148,"depth":413,"text":149},{"id":168,"depth":413,"text":169},{"id":184,"depth":408,"text":185},{"id":200,"depth":408,"text":201},{"id":216,"depth":408,"text":217},{"id":232,"depth":408,"text":233},{"id":351,"depth":408,"text":352},{"id":402,"depth":408,"text":403},"best-practices","2026-02-04","2026-02-25","Complete Vercel security best practices. Learn to configure security headers, protect environment variables, and secure your deployment pipeline.",false,"md",[432,433,434,435],{"question":327,"answer":330},{"question":333,"answer":336},{"question":339,"answer":342},{"question":345,"answer":348},"vercel",null,{},true,"Secure your Vercel deployments with proper headers, environment variable protection, and security configuration.","/blog/best-practices/vercel","12 min read","[object Object]","Article",{"title":5,"description":428},{"loc":441},"blog/best-practices/vercel",[],"summary_large_image","V8y6-Qn6LKXJJk6J8UXA6YjMjAOgEZzBrhKw5XeEK_c",1775843925164]