NextJS on Vercel: Auth and Secrets Configuration
Deploying a Next.js authentication system to Vercel requires more than pushing code: you must securely configure environment variables, connect to a production database, set up serverless functions to handle auth requests, and ensure secrets never leak. Vercel's edge functions and serverless infrastructure make deployment fast and secure, but misconfiguration is common. This guide walks through deploying a complete auth system to Vercel in production.
Preparing for Production Deployment
Before deploying, ensure your local environment is reproducible in production. Create a .env.example file documenting all required variables:
# .env.example (commit to git, no secrets)
DATABASE_URL=postgresql://user:password@localhost:5432/auth_db
REDIS_URL=redis://localhost:6379
SESSION_ENCRYPTION_KEY=your-hex-string-here
NEXTAUTH_URL=http://localhost:3000
NEXTAUTH_SECRET=your-secret-here
GITHUB_CLIENT_ID=
GITHUB_CLIENT_SECRET=
And a .env.local for local development (never commit):
# .env.local (add to .gitignore)
DATABASE_URL=postgresql://postgres:password@localhost:5432/auth_db
REDIS_URL=redis://localhost:6379
SESSION_ENCRYPTION_KEY=0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
NEXTAUTH_URL=http://localhost:3000
NEXTAUTH_SECRET=dev-secret
GITHUB_CLIENT_ID=dev-id
GITHUB_CLIENT_SECRET=dev-secret
Test that your app starts and authenticates locally:
npm run dev
# Visit http://localhost:3000/login and test login flow
Setting Up a Production Database
Vercel Postgres is a managed PostgreSQL database optimized for serverless. Create an account and set up a project:
# Install Vercel CLI
npm install -g vercel
# Login and link your project
vercel link
# Create a Vercel Postgres database
vercel env add DATABASE_URL
# The CLI will prompt for your database connection string
# Copy from Vercel dashboard: Settings > Integrations > Vercel Postgres
Vercel automatically encrypts secrets and injects them as environment variables on deployment. You can also use other databases (AWS RDS, Supabase, etc.); the connection string is the same.
Initialize the database schema in production. Create a migration file:
-- migrations/001_initial_schema.sql
CREATE TABLE users (
id TEXT PRIMARY KEY,
email TEXT UNIQUE NOT NULL,
password_hash TEXT NOT NULL,
role TEXT DEFAULT 'user',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE sessions (
id TEXT PRIMARY KEY,
user_id TEXT NOT NULL REFERENCES users(id),
role TEXT DEFAULT 'user',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
expires_at TIMESTAMP NOT NULL,
last_activity TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX idx_sessions_user_id ON sessions(user_id);
CREATE INDEX idx_sessions_expires_at ON sessions(expires_at);
Run the migration:
psql -d $DATABASE_URL -f migrations/001_initial_schema.sql
Or use a Node.js migration tool like db-migrate:
npm install db-migrate db-migrate-pg
db-migrate create initial_schema
# Edit migrations and run
db-migrate up
Configuring Vercel Environment Variables
In the Vercel dashboard, navigate to your project > Settings > Environment Variables. Add each secret:
-
Database Connection String:
- Key:
DATABASE_URL - Value: (copy from Vercel Postgres dashboard)
- Environments: Production, Preview, Development
- Key:
-
Session Encryption Key:
- Key:
SESSION_ENCRYPTION_KEY - Value: (generate with
openssl rand -hex 32) - Environments: Production, Preview, Development
- Key:
-
Auth Secret:
- Key:
NEXTAUTH_SECRET - Value: (generate with
openssl rand -hex 32) - Environments: Production, Preview, Development
- Key:
-
OAuth Secrets (if using GitHub/Google login):
- Key:
GITHUB_CLIENT_ID/GITHUB_CLIENT_SECRET - Value: (from GitHub OAuth app settings)
- Environments: Production, Preview
- Key:
-
Next Auth URL (important for production):
- Key:
NEXTAUTH_URL - Value:
https://yourdomain.com(production) orhttps://yourdomain.vercel.app(preview) - Environments: Production, Preview, Development
- Key:
For each environment variable, check which environments it applies to. Typically:
DATABASE_URL→ Production, Preview (production DB for previews)NEXTAUTH_URL→ Production, Preview (must match the deployment URL)GITHUB_CLIENT_SECRET→ Production (never expose in preview)
Deploying Authentication Code to Vercel
Push your code to GitHub, and Vercel automatically builds and deploys:
git add .
git commit -m "Add auth configuration for Vercel deployment"
git push origin main
Vercel detects the push, runs npm run build, and deploys to production. You can monitor the build in the Vercel dashboard. The deployment includes:
- Serverless functions for API routes and middleware.
- Static files (CSS, JS, images).
- Environment variables injected from the dashboard.
Testing Authentication in Production
After deployment, test the entire auth flow:
# Test login
curl -X POST https://yourdomain.com/api/login \
-H "Content-Type: application/json" \
-d '{"email":"[email protected]","password":"password123"}'
# Response should include a session cookie
# Test protected route
curl https://yourdomain.com/api/user/profile \
-H "Cookie: next_session=<session-id>"
# Response should include user profile
Also test in the browser:
- Visit
https://yourdomain.com/login - Enter credentials and submit
- Check cookies in DevTools (should see
next_sessioncookie withHttpOnlyflag) - Navigate to
/dashboard(should see authenticated content)
Monitoring and Logging in Production
Vercel integrates with logging and monitoring services. To debug auth issues, check:
-
Vercel Logs:
- Dashboard > Deployments > <deployment> > Logs
- Filter by
api/loginor other endpoints to see requests/errors
-
Database Logs:
- Vercel Postgres dashboard > Logs
- Check for connection errors or slow queries
-
External Monitoring:
- Integrate Sentry for error tracking:
npm install @sentry/nextjs - Set
SENTRY_DSNin environment variables - Errors are logged automatically
- Integrate Sentry for error tracking:
// sentry.server.config.ts
import * as Sentry from "@sentry/nextjs";
Sentry.init({
dsn: process.env.SENTRY_DSN,
integrations: [new Sentry.Integrations.OnUncaughtException()],
tracesSampleRate: 1.0,
});
Key Takeaways
- Use Vercel Postgres or another managed database for production auth.
- Configure all secrets in the Vercel dashboard, never commit them to git.
- Test authentication locally before deploying to ensure reproducibility.
- Set
NEXTAUTH_URLto match your production domain. - Monitor logs and errors in production to catch auth failures early.
- Use preview deployments to test auth changes on every pull request.
Frequently Asked Questions
How do I preview auth changes before deploying to production?
Push to a GitHub branch, and Vercel creates a preview deployment. The preview has its own URL (e.g., yourdomain-git-feature-branch.vercel.app). Add preview environment variables in the dashboard and test auth in the preview before merging to main.
Can I use a local database during development and Vercel Postgres in production?
Yes. Set DATABASE_URL in .env.local to your local database, and configure a different DATABASE_URL in Vercel dashboard for production. Vercel injects the correct value based on the environment.
How do I migrate data from development to production?
Use a database migration tool like db-migrate or write a Node.js script that connects to both databases and copies data. Do not export/import directly—SQL dumps can be large and insecure. For small tables (users, sessions), use INSERT INTO ... SELECT queries.
What if I accidentally commit a secret to git?
Revoke the secret immediately (regenerate it). Use git filter-branch to remove the commit history, or use a service like git-secrets to prevent future commits. Pushed secrets are visible in GitHub; assume they are compromised.