INTRO
Leaking an API key is usually not “someone read the repo” - it is `NEXT_PUBLIC_` on a secret, or a server key referenced from a Client Component. Next bundles `process.env.NEXT_PUBLIC_*` into the browser. Everything else is only safe on the server if you never pass it across the RSC wire to the client.
Public vs server-only variables
Prefix truly public config (analytics id, public map key with domain restrictions) with `NEXT_PUBLIC_`. Treat it as visible to every visitor.
Database URLs, signing secrets, admin tokens stay unprefixed and are only read in Server Components, Route Handlers, or server actions - never returned in props to client trees.
Build-time inlining vs runtime
On Vercel, env available at build can be baked into the bundle. If you need runtime-only secrets (rotating keys), use their runtime config patterns or load from a secret manager in server code paths.
Docker images: pass env at container start for server-only values; do not bake secrets into layers.
code-snippet.bash
# Server-only
DATABASE_URL=mongodb://...
SESSION_SECRET=...
# Safe for browser bundle
NEXT_PUBLIC_SITE_URL=https://example.comRotation and audit
Document who can see production env, and rotate after departures. Short-lived tokens beat one immortal API key.
Log which service account calls third-party APIs; it simplifies incident response.
KEY TAKEAWAYS
“Assume `NEXT_PUBLIC_*` is world-readable.”
- 02
Do not pass secrets into Client Components - even as props.
- 03
Understand build-time inlining vs runtime injection for your host.
CONCLUSION
Closing thought
Env hygiene is boring security. Prefix correctly, keep secrets on the server, and treat client bundles as hostile readers. Ready to talk scope? Use Contact — or browse Services for fit.
CONTINUE
Related pages
UP NEXT
Docker Multi-Stage Images for Node.js APIs and Workers
How I structure multi-stage builds for Express services: install, build, prune devDependencies, and run as a non-root user.
Read next article