Next.js cookbook · Beginner
Keep secrets and server code out of the client bundle
Make sure API keys and database code never ship to the browser in a Next.js app.
Approach
Only variables prefixed NEXT_PUBLIC_ are exposed to the browser; keep everything else unprefixed. Mark server modules with import "server-only" so importing them from a Client Component fails the build, and pass only the data the client needs (DTOs) from Server to Client Components.
Solution
// lib/db.ts
import "server-only";
import { PrismaClient } from "@prisma/client";
export const db = new PrismaClient();
// lib/stripe.ts
import "server-only";
import Stripe from "stripe";
export const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!);
// app/account/page.tsx (Server Component)
export default async function AccountPage() {
const session = await verifySession();
const user = await db.user.findUniqueOrThrow({ where: { id: session.userId } });
// FIX: pass a minimal DTO, not the full record (which may include passwordHash, tokens…)
return <ProfileForm user={{ name: user.name, email: user.email }} />;
}
# .env.local
DATABASE_URL=postgres://... # server only
STRIPE_SECRET_KEY=sk_live_... # server only
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=pk_live_... # intentionally public
Pitfalls
- Prefixing secrets with
NEXT_PUBLIC_to 'make it work'. - Passing whole database objects as props to Client Components (serialized into the page).
- Logging environment variables in build output.
Variations
- React's
experimental_taintObjectReference/taintUniqueValueto block specific objects/values from reaching the client.
Further reading: Next.js: Environment variables
Reference: https://nextjs.org/docs/app/guides/environment-variables
More Next.js recipes
- Add a Content Security Policy with nonces in Next.js
- Add dark mode to Next.js without a flash
- Add SEO metadata, Open Graph and sitemaps
- Avoid data-fetching waterfalls in Server Components
- Build a validated JSON API with Route Handlers
- Create encrypted session cookies in Next.js
- Handle errors and 404s in the App Router
- Handle forms with Server Actions and validation