Crash Courses · PhD
Environment Variables & Config
Manage environment variables, Next.js config, and TypeScript path aliases.
10 min read+200 XP on completionCert: Next.js Crash Course
Tap any word in the text below to start reading from there.
Environment Variables & Config
Environment Files — Priority Order
Next.js loads environment files in this order (highest to lowest priority):
.env.local ← highest — never committed (your local secrets)
.env.development ← dev builds only (npm run dev)
.env.production ← production builds only (npm run build)
.env ← all environments (lowest priority, commit safe for non-secrets)Create .env.local for local secrets. Add it to .gitignore (Next.js does this automatically).
Server vs Client Variables
# Server-only — NEVER shipped to the browser (no NEXT_PUBLIC_ prefix)
DATABASE_URL=postgresql://...
SUPABASE_SERVICE_ROLE_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
AZURE_SPEECH_KEY=abc123def456
STRIPE_SECRET_KEY=sk_live_...
# Browser-exposed — safe to expose, never put secrets here
NEXT_PUBLIC_SUPABASE_URL=https://xyz.supabase.co
NEXT_PUBLIC_APP_URL=https://academy.jsupremeconglomerate.online
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=pk_live_...The NEXT_PUBLIC_ vars are inlined at build time into the client bundle. If you accidentally put a secret in a NEXT_PUBLIC_ variable, it is visible to anyone who inspects the browser's network tab or JavaScript source.
TypeScript: Validate Env at Startup
// src/lib/env.ts — validates all required env vars when the server starts
import { z } from 'zod'
const envSchema = z.object({
DATABASE_URL: z.string().url(),
SUPABASE_SERVICE_ROLE_KEY: z.string().min(10),
AZURE_SPEECH_KEY: z.string().min(1),
NEXT_PUBLIC_SUPABASE_URL: z.string().url(),
NEXT_PUBLIC_APP_URL: z.string().url(),
})
export const env = envSchema.parse(process.env)
// Throws at startup if any required var is missing or malformed
// Prevents silent runtime failures mid-requestImport env from @/lib/env everywhere instead of process.env directly. You get autocomplete, type safety, and a server crash on startup (not a mid-request 500) if something is missing.
next.config.ts
import type { NextConfig } from 'next'
const config: NextConfig = {
// Allow images from these external domains
images: {
remotePatterns: [
{ protocol: 'https', hostname: '*.supabase.co' },
{ protocol: 'https', hostname: 'images.unsplash.com' },
],
},
// Add security headers to all API routes
async headers() {
return [{
source: '/api/:path*',
headers: [
{ key: 'X-Content-Type-Options', value: 'nosniff' },
{ key: 'X-Frame-Options', value: 'DENY' },
{ key: 'X-XSS-Protection', value: '1; mode=block' },
],
}]
},
// Permanent redirects
async redirects() {
return [{
source: '/old-path',
destination: '/new-path',
permanent: true, // 308 — tell search engines to update their index
}]
},
}
export default configtsconfig.json Path Aliases
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": ["./src/*"]
}
}
}With this configured:
import { COURSES } from '@/lib/courses'works from any file- No more
../../../lib/coursesrelative path gymnastics - Move files freely without updating import paths
Next.js's create-next-app sets this up automatically. If you are adding it manually, also set baseUrl and ensure the path alias matches your folder structure.
Reading progress
0% read
In this module
NEXT_PUBLIC_
.env.local
Path alias (@/)
next.config.ts
0%