Vercel Deployment Security: The Production Checklist for Next.js
Vercel makes deploying trivial — and makes a few security footguns trivial too. Here's the production checklist: env scoping, headers, preview protection, and the bundle leak everyone hits.

Easy to deploy, easy to leak
Vercel's developer experience is excellent, which means the security mistakes are also easy to make at speed. This checklist covers the Vercel-and-Next.js-specific ones.
1. The NEXT_PUBLIC_ bundle leak
Any env var prefixed NEXT_PUBLIC_ is inlined into the client bundle and shipped to every visitor. Developers routinely prefix a secret to "fix" an undefined variable and silently publish it.
# Only PUBLIC values should appear here:
grep -r "NEXT_PUBLIC_" .env*
Rule: NEXT_PUBLIC_* is for non-secret config only (analytics IDs, public anon keys). A Stripe secret key, a service-role key, or a database URL must never carry that prefix. If one did, rotate it — it's already public.
2. Environment scoping
Vercel has three environments: Production, Preview, Development. Don't reuse production secrets in preview — preview URLs are easier to discover and share. Scope secrets per environment in the dashboard, and use separate API keys/databases for preview where you can.
3. Protect preview deployments
Every push spins up a public preview URL. If your previews touch real data or expose unfinished admin tooling, enable Deployment Protection (Vercel Authentication or password) so previews aren't crawlable by anyone with the URL.
4. Security headers via config
Set headers once in next.config.js so every route is covered:
// next.config.js
const securityHeaders = [
{ key: "Strict-Transport-Security", value: "max-age=63072000; includeSubDomains; preload" },
{ key: "X-Content-Type-Options", value: "nosniff" },
{ key: "X-Frame-Options", value: "DENY" },
{ key: "Referrer-Policy", value: "strict-origin-when-cross-origin" },
{ key: "Content-Security-Policy", value: "default-src 'self'" },
];
module.exports = {
async headers() {
return [{ source: "/:path*", headers: securityHeaders }];
},
};
Confirm they actually ship:
curl -sI https://yourapp.vercel.app | grep -i "strict-transport\|content-security"
5. Lock down Route Handlers and Server Actions
- Every
app/api/*/route.tsis public by default — add auth checks inside. - Server Actions in modern Next.js validate the
OriginagainstallowedOrigins, but you still must authorize the action (is this user allowed to do this?). - Don't return internal error details to the client.
6. Don't trust middleware as your only auth gate
Next.js middleware runs on the edge and is fine for redirects, but it has historically had bypass edge cases and doesn't see everything. Enforce authorization at the data layer too (in the route handler / Server Component that reads data), not only in middleware.
7. Cron and webhook endpoints need secrets
Vercel Cron and external webhooks hit public URLs. Require a shared secret:
export async function GET(req: Request) {
if (req.headers.get("authorization") !== `Bearer ${process.env.CRON_SECRET}`) {
return new Response("Unauthorized", { status: 401 });
}
// ... do the job
}
For Stripe and similar, verify the signature, not just a bearer token.
8. Source maps and verbose builds
Avoid shipping source maps that expose your server logic to the browser in production, and make sure your error pages don't print stack traces.
9. Custom domains and HSTS preload
Once you're on a stable custom domain over HTTPS, consider submitting it to the HSTS preload list so browsers force HTTPS from the first visit.
10. Least-privilege integrations
Vercel integrations (databases, analytics) often request broad scopes. Grant the minimum, and review which integrations have access to your project periodically.
Pre-deploy checklist
- No secrets behind
NEXT_PUBLIC_ - Secrets scoped per environment
- Preview deployments protected
- Security headers in
next.config.jsand verified live - Route handlers/actions enforce auth + authorization
- Auth enforced at the data layer, not just middleware
- Cron/webhook endpoints require a secret or signature
- No production source maps / leaked stack traces
Treat preview as a separate security environment
A Vercel preview is not merely a smaller production URL. It can contain branch code, test integrations, comments, source-map clues and environment variables selected for the Preview environment. Use separate data and third-party credentials where possible, restrict access with Deployment Protection, and review who can create deployments from forks. Vercel documents Git fork protection specifically to reduce exposure of environment variables and OIDC tokens; disabling it should be an explicit risk decision.
Environment variables are encrypted at rest but visible to project members with access, and changes apply only to new deployments. After rotating a secret, redeploy every affected environment and invalidate the old credential at the provider. A successful dashboard edit does not modify an already-built deployment.
Prefer short-lived identity where integrations support it
For backend-to-backend access, Vercel documents OIDC federation so a deployment can present short-lived identity instead of storing a long-lived cloud credential. In May 2026 Vercel also introduced Trusted Sources for protected deployments, using OIDC tokens for authorized callers. Where that fits your provider, validate audience, subject and environment claims and keep an explicit fallback/revocation procedure.
Automation that must enter a protected deployment should use the documented protection mechanism, ideally a header-based bypass or supported OIDC path, rather than making the entire preview public. Store bypass material as a secret, scope the caller and rotate it when a CI integration is removed.
Verify the deployment, not just the repository
Create a release evidence sheet for production and preview separately: final URL and redirects, protection response, cache headers, CSP/HSTS and other security headers, exposed JavaScript strings, public source maps, runtime error behavior, cron/webhook authentication and the identity of connected integrations. Run the checks after the CDN because platform configuration can differ from local Next.js behavior.
Keep authorization in Route Handlers, Server Actions and the data layer even when a deployment is protected. Deployment Protection controls who can reach an environment; it does not decide whether an authenticated application user can mutate a particular record. The Next.js security practices cover that application boundary, while the Next.js + Supabase checklist adds database authorization.
Scan it with Troja
Troja checks your deployed Vercel app for the leaked NEXT_PUBLIC_ secret, missing headers, unprotected API routes, and exposed previews — then hands you a fix prompt for each. Point it at your production URL before your users (or attackers) find the gaps.
Frequently asked questions
Should Vercel preview deployments use production secrets?
Prefer separate preview credentials and data. Scope variables by environment, protect previews and assume preview URLs may be shared more widely than production. If a production secret must be used, document and minimize its permissions.
Does rotating a Vercel environment variable update existing deployments?
No. Vercel documents that environment-variable changes apply to new deployments. Revoke the old provider credential and redeploy every affected environment.
What does Vercel Git fork protection protect?
Vercel says it requires authorization before deploying pull requests from forks, helping prevent untrusted fork code from receiving project environment data such as variables and OIDC tokens.
Does Deployment Protection replace app authorization?
No. It gates access to a deployment. Route handlers, Server Actions and database operations still need identity, authorization and input validation for each protected action.
Sources and verification notes
Product capabilities are vendor-attributed and source-dated. Technical guidance uses primary documentation or vendor-neutral standards.
- Vercel environment variablesPrimary source for environment scoping, access and redeployment behavior.
- Vercel security settingsPrimary source for Git fork protection and OIDC-backed backend access.
- Vercel Deployment Protection bypass methodsPrimary source for supported automation and share workflows on protected deployments.
- Next.js data security guidePrimary framework source for keeping authorization at the application and data-access boundary.
Run the scan this post is about.
Free, no signup. See what's hiding inside your walls in ~30 seconds.
Keep reading
All posts
Next.js Security Best Practices: 10 Things Most Developers Miss
Next.js is secure by default — until you reach for client components, route handlers, and middleware. Here are ten places the framework's footguns hide, with the correct patterns.
Read
How to Secure Your Next.js + Supabase App: A Complete Security Checklist
The Next.js + Supabase stack is fast to ship and easy to leak. This end-to-end checklist covers RLS, the anon vs service key, auth, headers, and the bundle — with real code.
Read
SaaS Security Checklist Before Launch: The MVP Guide
Shipping your MVP this week? Run this pragmatic, prioritized security pass first — covering auth, multi-tenancy, secrets, payments, and the few headers that actually matter.
Read