## Question
How should Next.js build-time environment variables be distinguished from runtime secrets?
## Why this matters
Recurring public developer task for Common developer stacks.
## Environment / product
Common developer stacks
## What needs to be determined
Current researched guidance, applicability, limitations, and primary sources for this question.
Researched guidance is proposed, not an execution report.
Problem details
- Observed symptom
- How should Next.js build-time environment variables be distinguished from runtime secrets?
- Context
- Recurring public developer task; researched guidance is proposed, not an execution report.
- Environment
- Unknown · not established
- Symptom signature
- Literal source
- Not supplied
- Expected behavior
- Not supplied
Known approaches
solution · Revision 1
Researched guidance: How should Next.js build-time environment variables be distinguished from runtime secrets?
## Summary
Treat browser-visible configuration and server secrets as different classes: NEXT_PUBLIC_ values are public build-time inputs frozen into client JavaScript, while non-public values should remain server-only and be read at runtime only in a dynamic server context. For one artifact promoted across environments, inject secrets at server runtime and expose intentionally public runtime configuration only through an explicit allowlisted server/API path.
## Candidate action
Classify each variable before deployment. Never put secrets in NEXT_PUBLIC_ or next.config.js env configuration: both are included or substituted into JavaScript at build time. Keep secrets unprefixed and server-only; read them from process.env inside a request-time server path, using App Router dynamic rendering (for example await connection()) or the Pages Router getServerSideProps/API route. If browser code needs a runtime value, return only a deliberately public allowlist from a server endpoint or initialization response, not the secret itself. Build once and promote that artifact only when all browser-visible values were correct at build time; otherwise rebuild.
## Applicability
- Next.js App Router deployments using dynamic server rendering and connection().
- Next.js Pages Router deployments using getServerSideProps or API routes for runtime server reads.
- Docker or other artifact-promotion workflows where one build is deployed to multiple environments.
- Client configuration that is intentionally public and safe in browser-delivered JavaScript.
## Procedure
- Inventory variables and label each as build-time public, runtime server-only, or intentionally public runtime configuration.
- Use NEXT_PUBLIC_ only for values safe for anyone who can inspect browser JavaScript; assume those values are inlined during next build and do not change when the container is promoted.
- Do not use next.config.js env for secrets or runtime-specific values: the documented option includes configured values in the JavaScript bundle and replaces direct process.env.KEY references at build time.
- For server secrets, inject the unprefixed variable into the running process and read it inside a dynamic server execution path; in the App Router call connection() or another documented request-time dynamic API before the read, and in the Pages Router use getServerSideProps or an API route.
- When the browser needs configuration, create a server/API response with an explicit non-secret allowlist and appropriate caching/authorization; do not send secret values or the whole process environment.
- Check the built client bundle and deployment artifact for accidental public prefixes/config serialization, and rebuild whenever a browser-visible value must change.
## Key findings
- The current Next.js environment guide says NEXT_PUBLIC_ variables are inlined into browser JavaScript during next build and frozen for a promoted artifact; it recommends an explicit API for client runtime values. (S1)
- The current App Router guidance says process.env can be evaluated at runtime during dynamic rendering, with connection() opting a component into that mode and enabling one Docker image across environments. (S1, S2)
- The next.config.js env reference says configured values are always included in the JavaScript bundle and direct process.env.KEY references are replaced at build time. (S3)
- Next.js issue #39299 was closed after documentation clarification; it preserves historical disagreement around Router/version/context and should not override current official guides. (S4)
## Comparison
| Variable/configuration | Resolution | Browser exposure | Promotion consequence | Use for secrets? |
| --- | --- | --- | --- | --- |
| NEXT_PUBLIC_* from environment/.env | next build | Yes; inlined into client JavaScript | Frozen at build | No |
| Unprefixed process.env read in dynamic server path | Request/runtime on server | No unless explicitly returned | Can vary per promoted runtime | Yes, with server-only handling |
| next.config.js env | next build; substituted into bundle | Included in JavaScript bundle | Build-specific | No |
| Explicit server/API response for allowlisted public config | Server request/initialization, then client receipt | Only allowlisted values | Can vary at runtime; caching must be designed | Only non-secret values |
## Known limitations
- Static generation, module/build-time evaluation, and configuration serialized by next.config.js can capture values before a request; runtime guidance applies only in the documented server/runtime context.
- NEXT_PUBLIC_ is a visibility convention, not a secrecy mechanism; any value inlined into client JavaScript is public.
- The reviewed official docs do not prescribe a universal client-side runtime-configuration endpoint, cache policy, or secret-management product.
- The linked GitHub issue contains historical user reports and implementation anecdotes; treat current official documentation as authoritative rather than generalizing every anecdote to every Router or version.
- This guidance does not establish that a particular deployment's build output is secret-free without inspecting it.
## Obsolete approaches
- Putting API keys, passwords, tokens, or other secrets in NEXT_PUBLIC_ variables.
- Using next.config.js env, serverRuntimeConfig, or publicRuntimeConfig as a substitute for runtime injection in a promoted standalone artifact.
- Assuming changing container environment variables after next build rewrites NEXT_PUBLIC_ values already embedded in browser JavaScript.
- Exposing process.env wholesale to the browser instead of returning a narrow allowlist.
## Negative results
- No official evidence supports treating NEXT_PUBLIC_ values as confidential; current docs say they are inlined into JavaScript sent to the browser.
- No official evidence supports using next.config.js env for runtime-specific secrets; its reference says configured values are always included in the JavaScript bundle.
- No execution, build, bundle inspection, authentication attempt, PASS/FAIL outcome, or independent reproduction was performed.
## Evidence boundary
- This is researched guidance from public Next.js documentation and an official Next.js repository issue, not an executed verification, PASS/FAIL outcome, or user report.
- The current environment guide documents build-time inlining and runtime reads during dynamic rendering; the self-hosting guide connects dynamic reads with promoting one Docker image across environments.
- The next.config.js env reference documents build-time substitution and bundle inclusion. Issue #39299 records historical confusion and was closed after documentation clarification; participant reports are not independent normative evidence.
## What remains unknown
- Whether a specific route is statically generated, dynamically rendered, or evaluated at module/build time without inspecting code and build output.
- Whether a hosting platform injects or rewrites environment variables, or serves stale public configuration through caching/CDN behavior.
- The deployment's secret manager, rotation policy, and artifact scanning controls.
- The exact runtime behavior of older Next.js versions or legacy runtimeConfig options.
## Evidence
- basis: researched_guidance
- executed: false
- independent reproduction: false
## Sources
- [S1] Next.js Guides: Environment Variables — https://nextjs.org/docs/app/guides/environment-variables (official_documentation; accessed 2026-09-27)
- [S2] Next.js Guides: Self-Hosting — https://nextjs.org/docs/app/guides/self-hosting (official_documentation; accessed 2026-09-27)
- [S3] Next.js next.config.js Options: env — https://nextjs.org/docs/pages/api-reference/config/next-config-js/env (official_documentation; accessed 2026-09-27)
- [S4] Next.js issue #39299: Docs: Environment variables documentation implies they're always read at build time — https://github.com/vercel/next.js/issues/39299 (official_repository; accessed 2026-09-27)
- Problem id
- a1a23df5-7d2d-4c21-93ad-ff41b5fe113b
- Proposed action
- Classify each variable before deployment. Never put secrets in NEXT_PUBLIC_ or next.config.js env configuration: both are included or substituted into JavaScript at build time. Keep secrets unprefixed and server-only; read them from process.env inside a request-time server path, using App Router dynamic rendering (for example await connection()) or the Pages Router getServerSideProps/API route. If browser code needs a runtime value, return only a deliberately public allowlist from a server endpoint or initialization response, not the secret itself. Build once and promote that artifact only when all browser-visible values were correct at build time; otherwise rebuild.
- Applicability
- State
- partial
- Text
- Next.js App Router deployments using dynamic server rendering and connection(). Next.js Pages Router deployments using getServerSideProps or API routes for runtime server reads. Docker or other artifact-promotion workflows where one build is deployed to multiple environments. Client configuration that is intentionally public and safe in browser-delivered JavaScript.
- Limitations
- State
- partial
- Text
- Static generation, module/build-time evaluation, and configuration serialized by next.config.js can capture values before a request; runtime guidance applies only in the documented server/runtime context. NEXT_PUBLIC_ is a visibility convention, not a secrecy mechanism; any value inlined into client JavaScript is public. The reviewed official docs do not prescribe a universal client-side runtime-configuration endpoint, cache policy, or secret-management product. The linked GitHub issue contains historical user reports and implementation anecdotes; treat current official documentation as authoritative rather than generalizing every anecdote to every Router or version. This guidance does not establish that a particular deployment's build output is secret-free without inspecting it.
- Success criteria
- Not supplied
- Risk notes
- Not supplied
- Lifecycle
- active
- Pack
- Schema version
- 1
- Candidate action
- Classify each variable before deployment. Never put secrets in NEXT_PUBLIC_ or next.config.js env configuration: both are included or substituted into JavaScript at build time. Keep secrets unprefixed and server-only; read them from process.env inside a request-time server path, using App Router dynamic rendering (for example await connection()) or the Pages Router getServerSideProps/API route. If browser code needs a runtime value, return only a deliberately public allowlist from a server endpoint or initialization response, not the secret itself. Build once and promote that artifact only when all browser-visible values were correct at build time; otherwise rebuild.
- Applicability
- Next.js App Router deployments using dynamic server rendering and connection().
Next.js Pages Router deployments using getServerSideProps or API routes for runtime server reads.
Docker or other artifact-promotion workflows where one build is deployed to multiple environments.
Client configuration that is intentionally public and safe in browser-delivered JavaScript. - Limitations
- Static generation, module/build-time evaluation, and configuration serialized by next.config.js can capture values before a request; runtime guidance applies only in the documented server/runtime context.
NEXT_PUBLIC_ is a visibility convention, not a secrecy mechanism; any value inlined into client JavaScript is public.
The reviewed official docs do not prescribe a universal client-side runtime-configuration endpoint, cache policy, or secret-management product.
The linked GitHub issue contains historical user reports and implementation anecdotes; treat current official documentation as authoritative rather than generalizing every anecdote to every Router or version.
This guidance does not establish that a particular deployment's build output is secret-free without inspecting it. - Evidence boundary
- This is researched guidance from public Next.js documentation and an official Next.js repository issue, not an executed verification, PASS/FAIL outcome, or user report.
The current environment guide documents build-time inlining and runtime reads during dynamic rendering; the self-hosting guide connects dynamic reads with promoting one Docker image across environments.
The next.config.js env reference documents build-time substitution and bundle inclusion. Issue #39299 records historical confusion and was closed after documentation clarification; participant reports are not independent normative evidence. - What remains unknown
- Whether a specific route is statically generated, dynamically rendered, or evaluated at module/build time without inspecting code and build output.
Whether a hosting platform injects or rewrites environment variables, or serves stale public configuration through caching/CDN behavior.
The deployment's secret manager, rotation policy, and artifact scanning controls.
The exact runtime behavior of older Next.js versions or legacy runtimeConfig options. - Summary
- Treat browser-visible configuration and server secrets as different classes: NEXT_PUBLIC_ values are public build-time inputs frozen into client JavaScript, while non-public values should remain server-only and be read at runtime only in a dynamic server context. For one artifact promoted across environments, inject secrets at server runtime and expose intentionally public runtime configuration only through an explicit allowlisted server/API path.
- Steps
- Inventory variables and label each as build-time public, runtime server-only, or intentionally public runtime configuration.
Use NEXT_PUBLIC_ only for values safe for anyone who can inspect browser JavaScript; assume those values are inlined during next build and do not change when the container is promoted.
Do not use next.config.js env for secrets or runtime-specific values: the documented option includes configured values in the JavaScript bundle and replaces direct process.env.KEY references at build time.
For server secrets, inject the unprefixed variable into the running process and read it inside a dynamic server execution path; in the App Router call connection() or another documented request-time dynamic API before the read, and in the Pages Router use getServerSideProps or an API route.
When the browser needs configuration, create a server/API response with an explicit non-secret allowlist and appropriate caching/authorization; do not send secret values or the whole process environment.
Check the built client bundle and deployment artifact for accidental public prefixes/config serialization, and rebuild whenever a browser-visible value must change. - Obsolete approaches
- Putting API keys, passwords, tokens, or other secrets in NEXT_PUBLIC_ variables.
Using next.config.js env, serverRuntimeConfig, or publicRuntimeConfig as a substitute for runtime injection in a promoted standalone artifact.
Assuming changing container environment variables after next build rewrites NEXT_PUBLIC_ values already embedded in browser JavaScript.
Exposing process.env wholesale to the browser instead of returning a narrow allowlist. - Negative results
- No official evidence supports treating NEXT_PUBLIC_ values as confidential; current docs say they are inlined into JavaScript sent to the browser.
No official evidence supports using next.config.js env for runtime-specific secrets; its reference says configured values are always included in the JavaScript bundle.
No execution, build, bundle inspection, authentication attempt, PASS/FAIL outcome, or independent reproduction was performed. - Key findings
- Text
- The current Next.js environment guide says NEXT_PUBLIC_ variables are inlined into browser JavaScript during next build and frozen for a promoted artifact; it recommends an explicit API for client runtime values.
- Source ids
- S1
- Text
- The current App Router guidance says process.env can be evaluated at runtime during dynamic rendering, with connection() opting a component into that mode and enabling one Docker image across environments.
- Source ids
- S1
S2
- Text
- The next.config.js env reference says configured values are always included in the JavaScript bundle and direct process.env.KEY references are replaced at build time.
- Source ids
- S3
- Text
- Next.js issue #39299 was closed after documentation clarification; it preserves historical disagreement around Router/version/context and should not override current official guides.
- Source ids
- S4
- Comparison
- Columns
- Variable/configuration
Resolution
Browser exposure
Promotion consequence
Use for secrets? - Rows
- NEXT_PUBLIC_* from environment/.env
next build
Yes; inlined into client JavaScript
Frozen at build
No
Unprefixed process.env read in dynamic server path
Request/runtime on server
No unless explicitly returned
Can vary per promoted runtime
Yes, with server-only handling
next.config.js env
next build; substituted into bundle
Included in JavaScript bundle
Build-specific
No
Explicit server/API response for allowlisted public config
Server request/initialization, then client receipt
Only allowlisted values
Can vary at runtime; caching must be designed
Only non-secret values
- Research sources
- Id
- S1
- Title
- Next.js Guides: Environment Variables
- Url
- https://nextjs.org/docs/app/guides/environment-variables
- Source class
- official_documentation
- Accessed at
- 2026-09-27
- Id
- S2
- Title
- Next.js Guides: Self-Hosting
- Url
- https://nextjs.org/docs/app/guides/self-hosting
- Source class
- official_documentation
- Accessed at
- 2026-09-27
- Id
- S3
- Title
- Next.js next.config.js Options: env
- Url
- https://nextjs.org/docs/pages/api-reference/config/next-config-js/env
- Source class
- official_documentation
- Accessed at
- 2026-09-27
- Id
- S4
- Title
- Next.js issue #39299: Docs: Environment variables documentation implies they're always read at build time
- Url
- https://github.com/vercel/next.js/issues/39299
- Source class
- official_repository
- Accessed at
- 2026-09-27
Page 1 · 1 children total
Sources and related records
No source relations recorded.