Store secrets in .env, safely expose public values with NEXT_PUBLIC_, then build and deploy as a server or a static export.
Why: keep secrets (database URLs, API keys) out of your code and in a .env file, which is git-ignored. Next.js loads them into process.env automatically. Read them only in server code so they never reach the browser.
# .env (do not commit this file)
DATABASE_URL=postgres://localhost:5432/app
API_KEY=super-secret
// Read on the server (Server Component, action, or route handler):
const key = process.env.API_KEYWhy: only variables prefixed with NEXT_PUBLIC_ are sent to the browser — everything else stays server-only. So use the prefix for safe, public values (like an analytics ID), and never for secrets.
# .env
NEXT_PUBLIC_SITE_URL=https://example.com # available in the browser
SECRET_TOKEN=keep-this-private # server-only
'use client'
export function Footer() {
// Works in client code because of the NEXT_PUBLIC_ prefix:
return <a href={process.env.NEXT_PUBLIC_SITE_URL}>Home</a>
}Why: deploying means running the production build, not the dev server. build compiles and optimizes everything; start serves it as a Node.js server, which supports every Next.js feature. Most hosts run these two scripts for you.
$ pnpm build$ pnpm startpackage.json already wires these up: "dev": "next dev", "build": "next build", "start": "next start"
Why: if your site needs no server (no Server Actions, no dynamic APIs), export it to plain HTML/CSS/JS and host it anywhere — S3, GitHub Pages, any static host. Set output: "export" and build. Note: server-only features won’t work in this mode.
// next.config.ts
import type { NextConfig } from 'next'
const nextConfig: NextConfig = {
output: 'export', // build to static files in the out/ folder
}
export default nextConfig
// Then: pnpm build -> upload the generated out/ folder