new: drive vas from your AI agent over MCP · Cursor, Claude Code, Windsurf
Vercel
+
Supabase

Vercel + Supabase Security

Vercel and Supabase are a popular Next.js stack. Learn how to scope environment variables correctly, protect preview deployments, and ensure RLS guards your data.

Why Vercel + Supabase?

Vercel's native Supabase integration automatically injects environment variables into deployments, making this the default stack for Next.js developers who need a database. The convenience also creates consistent misconfiguration patterns.

Common Vulnerabilities

These are the security issues we find most often in Vercel apps using Supabase.

critical

NEXT_PUBLIC_ Prefix Exposes Service Key

The service_role key accidentally prefixed with NEXT_PUBLIC_ is bundled into client JavaScript and visible to every user.

high

Preview Deployments Share Production Credentials

By default, Vercel preview deployments use the same environment variable set as production, giving pull request previews access to live Supabase data.

critical

Missing RLS on Supabase Tables

Vercel makes deployment frictionless, which means apps reach production faster — before RLS has been configured on all tables.

high

Edge Functions Bypass Row-Level Auth

Vercel Edge Functions that use the service_role key to initialise Supabase skip RLS entirely, making every query fully privileged even when the caller is anonymous.

What We Check for Vercel + Supabase

Environment Variable Scoping

Verify service_role key is never prefixed with NEXT_PUBLIC_ and is absent from any client-side bundle.

Preview Deployment Isolation

Confirm preview deployments use a separate Supabase project or at minimum a read-only role, not production credentials.

RLS Coverage

Test all tables using the anon key to verify RLS blocks unauthorised access across both production and preview environments.

Edge vs Serverless Auth Context

Audit Vercel Edge Functions for service_role key usage and verify they pass the user JWT to Supabase when possible.

Quick Security Wins

Apply these fixes right now to improve your security.

In Vercel dashboard, set SUPABASE_SERVICE_ROLE_KEY with no NEXT_PUBLIC_ prefix and mark it as server-only
Create a separate Supabase project for preview deployments and add it to Vercel's Preview environment variable scope
Enable RLS on all tables: ALTER TABLE tablename ENABLE ROW LEVEL SECURITY;
Use createServerClient from @supabase/ssr in API routes and Server Components, createBrowserClient in client components
Add a vercel.json headers block for Content-Security-Policy and X-Frame-Options

The Bottom Line

Vercel + Supabase is a secure stack when environment variables are correctly scoped. The biggest risk is the service_role key reaching the client — check this before every deployment.

Secure Your Vercel + Supabase App

Find Row Level Security misconfigurations, exposed credentials, and other vulnerabilities before attackers do.

Start Security Scan

Frequently Asked Questions

How does Vercel's Supabase integration affect environment variable security?

Vercel's one-click Supabase integration injects NEXT_PUBLIC_SUPABASE_URL, NEXT_PUBLIC_SUPABASE_ANON_KEY, and SUPABASE_SERVICE_ROLE_KEY automatically. The first two are correctly public; the third is server-only. Verify none of your code accidentally uses the service_role key in a client context.

Should preview deployments use a different Supabase project?

Yes. Preview deployments from pull requests often include unreviewed code changes. Giving them production Supabase credentials means a bad PR can corrupt or expose live user data. Create a dedicated development Supabase project and point Vercel preview environments at it.

What is the correct Supabase client for Vercel Edge Functions?

Use createClient from @supabase/supabase-js with the anon key and pass the user's Authorization header as the auth token. This allows RLS to identify the user. Only use service_role in Edge Functions when you explicitly need to bypass RLS, and document why.

How do I add security headers to my Vercel + Supabase app?

Add a headers() configuration to next.config.js or a vercel.json headers block. Essential headers: Content-Security-Policy, X-Frame-Options: DENY, X-Content-Type-Options: nosniff, and Strict-Transport-Security. Vercel does not add these by default.