Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions crates/next-build-test/nextConfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@
"productionBrowserSourceMaps": false,
"optimizeFonts": true,
"excludeDefaultMomentLocales": true,
"serverRuntimeConfig": {},
"publicRuntimeConfig": {},
"reactProductionProfiling": false,
"reactStrictMode": true,
"httpAgentOptions": {
Expand Down
1 change: 1 addition & 0 deletions docs/01-app/02-guides/environment-variables.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,7 @@ This allows you to use a singular Docker image that can be promoted through mult
**Good to know:**

- You can run code on server startup using the [`register` function](/docs/app/guides/instrumentation).
- We do not recommend using the [`runtimeConfig`](/docs/pages/api-reference/config/next-config-js/runtime-configuration) option, as this does not work with the standalone output mode. Instead, we recommend [incrementally adopting](/docs/app/guides/migrating/app-router-migration) the App Router if you need this feature.

## Test Environment Variables

Expand Down
1 change: 1 addition & 0 deletions docs/01-app/02-guides/self-hosting.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ This allows you to use a singular Docker image that can be promoted through mult
> **Good to know:**
>
> - You can run code on server startup using the [`register` function](/docs/app/guides/instrumentation).
> - We do not recommend using the [runtimeConfig](/docs/pages/api-reference/config/next-config-js/runtime-configuration) option, as this does not work with the standalone output mode. Instead, we recommend [incrementally adopting](/docs/app/guides/migrating/app-router-migration) the App Router.

## Caching and ISR

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ node .next/standalone/server.js

> **Good to know**:
>
> - `next.config.js` is read during `next build` and serialized into the `server.js` output file.
> - `next.config.js` is read during `next build` and serialized into the `server.js` output file. If the legacy [`serverRuntimeConfig` or `publicRuntimeConfig` options](/docs/pages/api-reference/config/next-config-js/runtime-configuration) are being used, the values will be specific to values at build time.
> - If your project needs to listen to a specific port or hostname, you can define `PORT` or `HOSTNAME` environment variables before running `server.js`. For example, run `PORT=8080 HOSTNAME=0.0.0.0 node server.js` to start the server on `http://0.0.0.0:8080`.

</PagesOnly>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
---
title: Runtime Config
description: Add client and server runtime configuration to your Next.js app.
---

> **Warning:**
>
> - **This feature is deprecated.** We recommend using [environment variables](/docs/pages/guides/environment-variables) instead, which also can support reading runtime values.
> - You can run code on server startup using the [`register` function](/docs/app/guides/instrumentation).
> - This feature does not work with [Automatic Static Optimization](/docs/pages/building-your-application/rendering/automatic-static-optimization), [Output File Tracing](/docs/pages/api-reference/config/next-config-js/output#automatically-copying-traced-files), or [React Server Components](/docs/app/getting-started/server-and-client-components).

To add runtime configuration to your app, open `next.config.js` and add the `publicRuntimeConfig` and `serverRuntimeConfig` configs:

```js filename="next.config.js"
module.exports = {
serverRuntimeConfig: {
// Will only be available on the server side
mySecret: 'secret',
secondSecret: process.env.SECOND_SECRET, // Pass through env variables
},
publicRuntimeConfig: {
// Will be available on both server and client
staticFolder: '/static',
},
}
```

Place any server-only runtime config under `serverRuntimeConfig`.

Anything accessible to both client and server-side code should be under `publicRuntimeConfig`.

> A page that relies on `publicRuntimeConfig` **must** use `getInitialProps` or `getServerSideProps` or your application must have a [Custom App](/docs/pages/building-your-application/routing/custom-app) with `getInitialProps` to opt-out of [Automatic Static Optimization](/docs/pages/building-your-application/rendering/automatic-static-optimization). Runtime configuration won't be available to any page (or component in a page) without being server-side rendered.

To get access to the runtime configs in your app use `next/config`, like so:

```jsx
import getConfig from 'next/config'
import Image from 'next/image'

// Only holds serverRuntimeConfig and publicRuntimeConfig
const { serverRuntimeConfig, publicRuntimeConfig } = getConfig()
// Will only be available on the server-side
console.log(serverRuntimeConfig.mySecret)
// Will be available on both server-side and client-side
console.log(publicRuntimeConfig.staticFolder)

function MyImage() {
return (
<div>
<Image
src={`${publicRuntimeConfig.staticFolder}/logo.png`}
alt="logo"
layout="fill"
/>
</div>
)
}

export default MyImage
```
3 changes: 3 additions & 0 deletions packages/next/config.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import getConfig from './dist/shared/lib/runtime-config.external'
export * from './dist/shared/lib/runtime-config.external'
export default getConfig
1 change: 1 addition & 0 deletions packages/next/config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module.exports = require('./dist/shared/lib/runtime-config.external')
1 change: 1 addition & 0 deletions packages/next/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
/// <reference path="./amp.d.ts" />
/// <reference path="./app.d.ts" />
/// <reference path="./cache.d.ts" />
/// <reference path="./config.d.ts" />
/// <reference path="./document.d.ts" />
/// <reference path="./dynamic.d.ts" />
/// <reference path="./error.d.ts" />
Expand Down
9 changes: 8 additions & 1 deletion packages/next/src/build/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1909,7 +1909,9 @@ export default async function build(
}
}

const { configFileName } = config
const { configFileName, publicRuntimeConfig, serverRuntimeConfig } =
config
const runtimeEnvConfig = { publicRuntimeConfig, serverRuntimeConfig }
const sriEnabled = Boolean(config.experimental.sri?.algorithm)

const nonStaticErrorPageSpan = staticCheckSpan.traceChild(
Expand All @@ -1922,6 +1924,7 @@ export default async function build(
(await worker.hasCustomGetInitialProps({
page: '/_error',
distDir,
runtimeEnvConfig,
checkingApp: false,
sriEnabled,
}))
Expand All @@ -1935,6 +1938,7 @@ export default async function build(
page: '/_error',
distDir,
configFileName,
runtimeEnvConfig,
cacheComponents: isAppCacheComponentsEnabled,
authInterrupts: isAuthInterruptsEnabled,
httpAgentOptions: config.httpAgentOptions,
Expand All @@ -1954,6 +1958,7 @@ export default async function build(
? worker.hasCustomGetInitialProps({
page: appPageToCheck,
distDir,
runtimeEnvConfig,
checkingApp: true,
sriEnabled,
})
Expand All @@ -1963,6 +1968,7 @@ export default async function build(
? worker.getDefinedNamedExports({
page: appPageToCheck,
distDir,
runtimeEnvConfig,
sriEnabled,
})
: Promise.resolve([])
Expand Down Expand Up @@ -2149,6 +2155,7 @@ export default async function build(
originalAppPath,
distDir,
configFileName,
runtimeEnvConfig,
httpAgentOptions: config.httpAgentOptions,
locales: config.i18n?.locales,
defaultLocale: config.i18n?.defaultLocale,
Expand Down
6 changes: 6 additions & 0 deletions packages/next/src/build/templates/edge-ssr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,12 @@ async function requestHandler(
distDir: '',
crossOrigin: nextConfig.crossOrigin ? nextConfig.crossOrigin : undefined,
largePageDataBytes: nextConfig.experimental.largePageDataBytes,
// Only the `publicRuntimeConfig` key is exposed to the client side
// It'll be rendered as part of __NEXT_DATA__ on the client side
runtimeConfig:
Object.keys(nextConfig.publicRuntimeConfig).length > 0
? nextConfig.publicRuntimeConfig
: undefined,

isExperimentalCompile: nextConfig.experimental.isExperimentalCompile,
// `htmlLimitedBots` is passed to server as serialized config in string format
Expand Down
16 changes: 16 additions & 0 deletions packages/next/src/build/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -567,6 +567,7 @@ export async function isPageStatic({
page,
distDir,
configFileName,
runtimeEnvConfig,
httpAgentOptions,
locales,
defaultLocale,
Expand All @@ -593,6 +594,7 @@ export async function isPageStatic({
cacheComponents: boolean
authInterrupts: boolean
configFileName: string
runtimeEnvConfig: any
httpAgentOptions: NextConfigComplete['httpAgentOptions']
locales?: readonly string[]
defaultLocale?: string
Expand Down Expand Up @@ -642,6 +644,9 @@ export async function isPageStatic({
const isPageStaticSpan = trace('is-page-static-utils', parentId)
return isPageStaticSpan
.traceAsyncFn(async (): Promise<PageIsStaticResult> => {
;(
require('../shared/lib/runtime-config.external') as typeof import('../shared/lib/runtime-config.external')
).setConfig(runtimeEnvConfig)
setHttpClientAndAgentOptions({
httpAgentOptions,
})
Expand Down Expand Up @@ -950,14 +955,20 @@ export function reduceAppConfig(
export async function hasCustomGetInitialProps({
page,
distDir,
runtimeEnvConfig,
checkingApp,
sriEnabled,
}: {
page: string
distDir: string
runtimeEnvConfig: any
checkingApp: boolean
sriEnabled: boolean
}): Promise<boolean> {
;(
require('../shared/lib/runtime-config.external') as typeof import('../shared/lib/runtime-config.external')
).setConfig(runtimeEnvConfig)

const { ComponentMod } = await loadComponents({
distDir,
page: page,
Expand All @@ -980,12 +991,17 @@ export async function hasCustomGetInitialProps({
export async function getDefinedNamedExports({
page,
distDir,
runtimeEnvConfig,
sriEnabled,
}: {
page: string
distDir: string
runtimeEnvConfig: any
sriEnabled: boolean
}): Promise<ReadonlyArray<string>> {
;(
require('../shared/lib/runtime-config.external') as typeof import('../shared/lib/runtime-config.external')
).setConfig(runtimeEnvConfig)
const { ComponentMod } = await loadComponents({
distDir,
page: page,
Expand Down
7 changes: 7 additions & 0 deletions packages/next/src/client/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import {
urlQueryToSearchParams,
assign,
} from '../shared/lib/router/utils/querystring'
import { setConfig } from '../shared/lib/runtime-config.external'
import { getURL, loadGetInitialProps, ST } from '../shared/lib/utils'
import type { NextWebVitalsMetric, NEXT_DATA } from '../shared/lib/utils'
import { Portal } from './portal'
Expand Down Expand Up @@ -211,6 +212,12 @@ export async function initialize(opts: { devClient?: any } = {}): Promise<{
// So, this is how we do it in the client side at runtime
;(self as any).__next_set_public_path__(`${prefix}/_next/`) //eslint-disable-line

// Initialize next/config with the environment configuration
setConfig({
serverRuntimeConfig: {},
publicRuntimeConfig: initialData.runtimeConfig || {},
})

asPath = getURL()

// make sure not to attempt stripping basePath for 404s
Expand Down
6 changes: 6 additions & 0 deletions packages/next/src/export/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -422,6 +422,12 @@ async function exportAppImpl(
nextConfig.experimental.enablePrerenderSourceMaps === true,
}

const { publicRuntimeConfig } = nextConfig

if (Object.keys(publicRuntimeConfig).length > 0) {
renderOpts.runtimeConfig = publicRuntimeConfig
}

// We need this for server rendering the Link component.
;(globalThis as any).__NEXT_DATA__ = {
nextExport: true,
Expand Down
1 change: 1 addition & 0 deletions packages/next/src/export/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ export interface ExportPageInput {
ampValidatorPath?: string
trailingSlash?: boolean
buildExport?: boolean
serverRuntimeConfig: { [key: string]: any }
subFolders?: boolean
optimizeCss: any
disableOptimizedLoading: any
Expand Down
11 changes: 11 additions & 0 deletions packages/next/src/export/worker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,10 @@ import type { PagesRenderContext, PagesSharedContext } from '../server/render'
import type { AppSharedContext } from '../server/app-render/app-render'
import { MultiFileWriter } from '../lib/multi-file-writer'
import { createRenderResumeDataCache } from '../server/resume-data-cache/resume-data-cache'

const envConfig =
require('../shared/lib/runtime-config.external') as typeof import('../shared/lib/runtime-config.external')

;(globalThis as any).__NEXT_DATA__ = {
nextExport: true,
}
Expand All @@ -71,6 +75,7 @@ async function exportPageImpl(
distDir,
pagesDataDir,
buildExport = false,
serverRuntimeConfig,
subFolders = false,
optimizeCss,
disableOptimizedLoading,
Expand Down Expand Up @@ -191,6 +196,11 @@ async function exportPageImpl(
addRequestMeta(req, 'isLocaleDomain', true)
}

envConfig.setConfig({
serverRuntimeConfig,
publicRuntimeConfig: commonRenderOpts.runtimeConfig,
})

const getHtmlFilename = (p: string) =>
subFolders ? `${p}${sep}index.html` : `${p}.html`

Expand Down Expand Up @@ -406,6 +416,7 @@ export async function exportPages(
ampValidatorPath:
nextConfig.experimental.amp?.validator || undefined,
trailingSlash: nextConfig.trailingSlash,
serverRuntimeConfig: nextConfig.serverRuntimeConfig,
subFolders: nextConfig.trailingSlash && !options.buildExport,
buildExport: options.buildExport,
optimizeCss: nextConfig.experimental.optimizeCss,
Expand Down
22 changes: 21 additions & 1 deletion packages/next/src/server/base-server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ import {
UNDERSCORE_NOT_FOUND_ROUTE_ENTRY,
} from '../shared/lib/constants'
import { isDynamicRoute } from '../shared/lib/router/utils'
import { setConfig } from '../shared/lib/runtime-config.external'
import { execOnce } from '../shared/lib/utils'
import { isBlockedPage } from './utils'
import { getBotType, isBot } from '../shared/lib/router/utils/is-bot'
Expand Down Expand Up @@ -474,7 +475,14 @@ export default abstract class Server<
? new LocaleRouteNormalizer(this.i18nProvider)
: undefined

const { assetPrefix, generateEtags } = this.nextConfig
// Only serverRuntimeConfig needs the default
// publicRuntimeConfig gets it's default in client/index.js
const {
serverRuntimeConfig = {},
publicRuntimeConfig,
assetPrefix,
generateEtags,
} = this.nextConfig

this.buildId = this.getBuildId()
// this is a hack to avoid Webpack knowing this is equal to this.minimalMode
Expand Down Expand Up @@ -543,6 +551,12 @@ export default abstract class Server<
? this.nextConfig.crossOrigin
: undefined,
largePageDataBytes: this.nextConfig.experimental.largePageDataBytes,
// Only the `publicRuntimeConfig` key is exposed to the client side
// It'll be rendered as part of __NEXT_DATA__ on the client side
runtimeConfig:
Object.keys(publicRuntimeConfig).length > 0
? publicRuntimeConfig
: undefined,

isExperimentalCompile: this.nextConfig.experimental.isExperimentalCompile,
// `htmlLimitedBots` is passed to server as serialized config in string format
Expand All @@ -569,6 +583,12 @@ export default abstract class Server<
reactMaxHeadersLength: this.nextConfig.reactMaxHeadersLength,
}

// Initialize next/config with the environment configuration
setConfig({
serverRuntimeConfig,
publicRuntimeConfig,
})

this.pagesManifest = this.getPagesManifest()
this.appPathsManifest = this.getAppPathsManifest()
this.appPathRoutes = this.getAppPathRoutes()
Expand Down
2 changes: 2 additions & 0 deletions packages/next/src/server/config-schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -653,6 +653,7 @@ export const configSchema: zod.ZodType<NextConfig> = z.lazy(() =>
pageExtensions: z.array(z.string()).min(1).optional(),
poweredByHeader: z.boolean().optional(),
productionBrowserSourceMaps: z.boolean().optional(),
publicRuntimeConfig: z.record(z.string(), z.any()).optional(),
reactProductionProfiling: z.boolean().optional(),
reactStrictMode: z.boolean().nullable().optional(),
reactMaxHeadersLength: z.number().nonnegative().int().optional(),
Expand Down Expand Up @@ -685,6 +686,7 @@ export const configSchema: zod.ZodType<NextConfig> = z.lazy(() =>
.catchall(z.any())
.optional(),
serverExternalPackages: z.array(z.string()).optional(),
serverRuntimeConfig: z.record(z.string(), z.any()).optional(),
skipMiddlewareUrlNormalize: z.boolean().optional(),
skipTrailingSlashRedirect: z.boolean().optional(),
staticPageGenerationTimeout: z.number().optional(),
Expand Down
Loading
Loading