Repository: vercel/next.js
Pull request: Also enforce experimental features when there's no next config file

When running `next build --debug-prerender`, we also want to set the experimental features even if there is no next.config.js file present.

This PR also fixes the `cloneObject` function to better handle nested optional object properties, and we're now also freezing and cloning the default config before applying changes to it.

> [!NOTE]  
> This PR is best reviewed with hidden whitespace changes.

Changed files:
filename: packages/next/src/server/config-shared.ts
patch: @@ -1283,7 +1283,7 @@ export interface NextConfig extends Record<string, any> {
   htmlLimitedBots?: RegExp
 }
 
-export const defaultConfig = {
+export const defaultConfig = Object.freeze({
   env: {},
   webpack: null,
   eslint: {
@@ -1503,7 +1503,7 @@ export const defaultConfig = {
   },
   htmlLimitedBots: undefined,
   bundlePagesRouterDependencies: false,
-} satisfies NextConfig
+} satisfies NextConfig)
 
 export async function normalizeConfig(phase: string, config: any) {
   if (typeof config === 'function') {

filename: packages/next/src/server/config.ts
patch: @@ -1227,6 +1227,7 @@ export default async function loadConfig(
   }
 
   const path = await findUp(CONFIG_FILES, { cwd: dir })
+  const configuredExperimentalFeatures: ConfiguredExperimentalFeature[] = []
 
   // If config file was found
   if (path?.length) {
@@ -1280,8 +1281,6 @@ export default async function loadConfig(
       )) as NextConfig
     )
 
-    const configuredExperimentalFeatures: ConfiguredExperimentalFeature[] = []
-
     if (reportExperimentalFeatures && loadedConfig.experimental) {
       for (const name of Object.keys(
         loadedConfig.experimental
@@ -1420,58 +1419,13 @@ export default async function loadConfig(
       userConfig.htmlLimitedBots = userConfig.htmlLimitedBots.source
     }
 
-    if (
-      userConfig.experimental &&
-      userConfig.experimental.enablePrerenderSourceMaps === undefined &&
-      userConfig.experimental.dynamicIO === true
-    ) {
-      userConfig.experimental.enablePrerenderSourceMaps = true
-      addConfiguredExperimentalFeature(
-        configuredExperimentalFeatures,
-        'enablePrerenderSourceMaps',
-        true,
-        'enabled by `experimental.dynamicIO`'
-      )
-    }
-
-    if (
-      debugPrerender &&
-      (phase === PHASE_PRODUCTION_BUILD || phase === PHASE_EXPORT)
-    ) {
-      userConfig.experimental ??= {}
-
-      setExperimentalFeatureForDebugPrerender(
-        userConfig.experimental,
-        'serverSourceMaps',
-        true,
-        reportExperimentalFeatures ? configuredExperimentalFeatures : undefined
-      )
-
-      setExperimentalFeatureForDebugPrerender(
-        userConfig.experimental,
-        process.env.TURBOPACK ? 'turbopackMinify' : 'serverMinification',
-        false,
-        reportExperimentalFeatures ? configuredExperimentalFeatures : undefined
-      )
-
-      setExperimentalFeatureForDebugPrerender(
-        userConfig.experimental,
-        'enablePrerenderSourceMaps',
-        true,
-        reportExperimentalFeatures ? configuredExperimentalFeatures : undefined
-      )
-
-      setExperimentalFeatureForDebugPrerender(
-        userConfig.experimental,
-        'prerenderEarlyExit',
-        false,
-        reportExperimentalFeatures ? configuredExperimentalFeatures : undefined
-      )
-    }
-
-    if (reportExperimentalFeatures) {
-      reportExperimentalFeatures(configuredExperimentalFeatures)
-    }
+    enforceExperimentalFeatures(userConfig, {
+      configuredExperimentalFeatures: reportExperimentalFeatures
+        ? configuredExperimentalFeatures
+        : undefined,
+      debugPrerender,
+      phase,
+    })
 
     const completeConfig = assignDefaults(
       dir,
@@ -1483,6 +1437,11 @@ export default async function loadConfig(
       },
       silent
     ) as NextConfigComplete
+
+    if (reportExperimentalFeatures) {
+      reportExperimentalFeatures(configuredExperimentalFeatures)
+    }
+
     return await applyModifyConfig(completeConfig, phase, silent)
   } else {
     const configBaseName = basename(CONFIG_FILES[0], extname(CONFIG_FILES[0]))
@@ -1506,14 +1465,30 @@ export default async function loadConfig(
     }
   }
 
+  const clonedDefaultConfig = cloneObject(defaultConfig) as NextConfig
+
+  enforceExperimentalFeatures(clonedDefaultConfig, {
+    configuredExperimentalFeatures: reportExperimentalFeatures
+      ? configuredExperimentalFeatures
+      : undefined,
+    debugPrerender,
+    phase,
+  })
+
   // always call assignDefaults to ensure settings like
   // reactRoot can be updated correctly even with no next.config.js
   const completeConfig = assignDefaults(
     dir,
-    { ...defaultConfig, configFileName },
+    { ...clonedDefaultConfig, configFileName },
     silent
   ) as NextConfigComplete
+
   setHttpClientAndAgentOptions(completeConfig)
+
+  if (reportExperimentalFeatures) {
+    reportExperimentalFeatures(configuredExperimentalFeatures)
+  }
+
   return await applyModifyConfig(completeConfig, phase, silent)
 }
 
@@ -1523,7 +1498,70 @@ export type ConfiguredExperimentalFeature = {
   reason?: string
 }
 
-export function addConfiguredExperimentalFeature<
+function enforceExperimentalFeatures(
+  config: NextConfig,
+  options: {
+    configuredExperimentalFeatures: ConfiguredExperimentalFeature[] | undefined
+    debugPrerender: boolean | undefined
+    phase: string
+  }
+) {
+  const { configuredExperimentalFeatures, debugPrerender, phase } = options
+
+  if (
+    config.experimental &&
+    config.experimental.enablePrerenderSourceMaps === undefined &&
+    config.experimental.dynamicIO === true
+  ) {
+    config.experimental.enablePrerenderSourceMaps = true
+
+    if (configuredExperimentalFeatures) {
+      addConfiguredExperimentalFeature(
+        configuredExperimentalFeatures,
+        'enablePrerenderSourceMaps',
+        true,
+        'enabled by `experimental.dynamicIO`'
+      )
+    }
+  }
+
+  config.experimental ??= {}
+
+  if (
+    debugPrerender &&
+    (phase === PHASE_PRODUCTION_BUILD || phase === PHASE_EXPORT)
+  ) {
+    setExperimentalFeatureForDebugPrerender(
+      config.experimental,
+      'serverSourceMaps',
+      true,
+      configuredExperimentalFeatures
+    )
+
+    setExperimentalFeatureForDebugPrerender(
+      config.experimental,
+      process.env.TURBOPACK ? 'turbopackMinify' : 'serverMinification',
+      false,
+      configuredExperimentalFeatures
+    )
+
+    setExperimentalFeatureForDebugPrerender(
+      config.experimental,
+      'enablePrerenderSourceMaps',
+      true,
+      configuredExperimentalFeatures
+    )
+
+    setExperimentalFeatureForDebugPrerender(
+      config.experimental,
+      'prerenderEarlyExit',
+      false,
+      configuredExperimentalFeatures
+    )
+  }
+}
+
+function addConfiguredExperimentalFeature<
   KeyType extends keyof ExperimentalConfig,
 >(
   configuredExperimentalFeatures: ConfiguredExperimentalFeature[],
@@ -1564,20 +1602,50 @@ function setExperimentalFeatureForDebugPrerender<
 }
 
 function cloneObject(obj: any): any {
+  // Primitives & null
   if (obj === null || typeof obj !== 'object') {
     return obj
   }
 
+  // RegExp → clone via constructor
+  if (obj instanceof RegExp) {
+    return new RegExp(obj.source, obj.flags)
+  }
+
+  // Function → just reuse the function reference
+  if (typeof obj === 'function') {
+    return obj
+  }
+
+  // Arrays → map each element
   if (Array.isArray(obj)) {
     return obj.map(cloneObject)
   }
-  const keys = Object.keys(obj)
-  if (keys.length === 0) {
+
+  // Detect non‑plain objects (class instances)
+  const proto = Object.getPrototypeOf(obj)
+  const isPlainObject = proto === Object.prototype || proto === null
+
+  // If it's not a plain object, just return the original
+  if (!isPlainObject) {
     return obj
   }
 
-  return keys.reduce((acc, key) => {
-    ;(acc as any)[key] = cloneObject(obj[key])
-    return acc
-  }, {})
+  // Plain object → create a new object with the same prototype
+  // and copy all properties, cloning data properties and keeping
+  // accessor properties (getters/setters) as‑is.
+  const result = Object.create(proto)
+  for (const key of Reflect.ownKeys(obj)) {
+    const descriptor = Object.getOwnPropertyDescriptor(obj, key)
+
+    if (descriptor && (descriptor.get || descriptor.set)) {
+      // Accessor property → copy descriptor as‑is (get/set functions)
+      Object.defineProperty(result, key, descriptor)
+    } else {
+      // Data property → clone the value
+      result[key] = cloneObject(obj[key])
+    }
+  }
+
+  return result
 }

filename: test/production/app-dir/build-output-prerender/build-output-prerender.test.ts
patch: @@ -1,154 +1,214 @@
 import { nextTestSetup } from 'e2e-utils'
+import path from 'path'
 const { version: nextVersion } = require('next/package.json')
 
 describe('build-output-prerender', () => {
-  describe('without --debug-prerender', () => {
-    const { next, isTurbopack } = nextTestSetup({
-      files: __dirname,
-      skipStart: true,
-    })
+  describe('with a next config file', () => {
+    describe('without --debug-prerender', () => {
+      const { next, isTurbopack } = nextTestSetup({
+        files: path.join(__dirname, 'fixtures/with-config-file'),
+        skipStart: true,
+      })
+
+      beforeAll(() => next.build())
+
+      it('prints only the user-selected experimental flags', async () => {
+        if (isTurbopack) {
+          expect(getPreambleOutput(next.cliOutput)).toMatchInlineSnapshot(`
+           "▲ Next.js x.y.z (Turbopack)
+              - Experiments (use with caution):
+                ✓ dynamicIO
+                ✓ enablePrerenderSourceMaps (enabled by \`experimental.dynamicIO\`)"
+          `)
+        } else {
+          expect(getPreambleOutput(next.cliOutput)).toMatchInlineSnapshot(`
+           "▲ Next.js x.y.z
+              - Experiments (use with caution):
+                ✓ dynamicIO
+                ✓ enablePrerenderSourceMaps (enabled by \`experimental.dynamicIO\`)"
+          `)
+        }
+      })
 
-    beforeAll(() => next.build())
-
-    it('prints only the user-selected experimental flags', async () => {
-      if (isTurbopack) {
-        expect(getPreambleOutput(next.cliOutput)).toMatchInlineSnapshot(`
-         "▲ Next.js x.y.z (Turbopack)
-            - Experiments (use with caution):
-              ✓ dynamicIO
-              ✓ enablePrerenderSourceMaps (enabled by \`experimental.dynamicIO\`)"
-        `)
-      } else {
-        expect(getPreambleOutput(next.cliOutput)).toMatchInlineSnapshot(`
-         "▲ Next.js x.y.z
-            - Experiments (use with caution):
-              ✓ dynamicIO
-              ✓ enablePrerenderSourceMaps (enabled by \`experimental.dynamicIO\`)"
-        `)
-      }
+      it('shows only a single prerender error with a mangled stack', async () => {
+        if (isTurbopack) {
+          // TODO(veil): Why is the location incomplete unless we enable --no-mangling?
+          expect(getPrerenderOutput(next.cliOutput)).toMatchInlineSnapshot(`
+           "Error: Route "/client" used \`new Date()\` inside a Client Component without a Suspense boundary above it. See more info here: https://nextjs.org/docs/messages/next-prerender-current-time-client
+               at c (turbopack:///[project]/app/client/page.tsx:5:0)
+             3 | export default function Page() {
+             4 |   return <p>Current time: {new Date().toISOString()}</p>
+           > 5 | }
+             6 |
+           To get a more detailed stack trace and pinpoint the issue, try one of the following:
+             - Start the app in development mode by running \`next dev\`, then open "/client" in your browser to investigate the error.
+             - Rerun the production build with \`next build --debug-prerender\` to generate better stack traces.
+           Error occurred prerendering page "/client". Read more: https://nextjs.org/docs/messages/prerender-error
+           Export encountered an error on /client/page: /client, exiting the build."
+          `)
+        } else {
+          expect(getPrerenderOutput(next.cliOutput)).toMatchInlineSnapshot(`
+           "Error: Route "/client" used \`new Date()\` inside a Client Component without a Suspense boundary above it. See more info here: https://nextjs.org/docs/messages/next-prerender-current-time-client
+               at x (<next-dist-dir>)
+           To get a more detailed stack trace and pinpoint the issue, try one of the following:
+             - Start the app in development mode by running \`next dev\`, then open "/client" in your browser to investigate the error.
+             - Rerun the production build with \`next build --debug-prerender\` to generate better stack traces.
+           Error occurred prerendering page "/client". Read more: https://nextjs.org/docs/messages/prerender-error
+           Export encountered an error on /client/page: /client, exiting the build."
+          `)
+        }
+      })
     })
 
-    it('shows only a single prerender error with a mangled stack', async () => {
-      if (isTurbopack) {
-        // TODO(veil): Why is the location incomplete unless we enable --no-mangling?
-        expect(getPrerenderOutput(next.cliOutput)).toMatchInlineSnapshot(`
-         "Error: Route "/client" used \`new Date()\` inside a Client Component without a Suspense boundary above it. See more info here: https://nextjs.org/docs/messages/next-prerender-current-time-client
-             at c (turbopack:///[project]/app/client/page.tsx:5:0)
-           3 | export default function Page() {
-           4 |   return <p>Current time: {new Date().toISOString()}</p>
-         > 5 | }
-           6 |
-         To get a more detailed stack trace and pinpoint the issue, try one of the following:
-           - Start the app in development mode by running \`next dev\`, then open "/client" in your browser to investigate the error.
-           - Rerun the production build with \`next build --debug-prerender\` to generate better stack traces.
-         Error occurred prerendering page "/client". Read more: https://nextjs.org/docs/messages/prerender-error
-         Export encountered an error on /client/page: /client, exiting the build."
-        `)
-      } else {
-        expect(getPrerenderOutput(next.cliOutput)).toMatchInlineSnapshot(`
-         "Error: Route "/client" used \`new Date()\` inside a Client Component without a Suspense boundary above it. See more info here: https://nextjs.org/docs/messages/next-prerender-current-time-client
-             at x (<next-dist-dir>)
-         To get a more detailed stack trace and pinpoint the issue, try one of the following:
-           - Start the app in development mode by running \`next dev\`, then open "/client" in your browser to investigate the error.
-           - Rerun the production build with \`next build --debug-prerender\` to generate better stack traces.
-         Error occurred prerendering page "/client". Read more: https://nextjs.org/docs/messages/prerender-error
-         Export encountered an error on /client/page: /client, exiting the build."
-        `)
-      }
+    describe('with --debug-prerender', () => {
+      const { next, isTurbopack } = nextTestSetup({
+        files: path.join(__dirname, 'fixtures/with-config-file'),
+        skipStart: true,
+        buildArgs: ['--debug-prerender'],
+      })
+
+      beforeAll(() => next.build())
+
+      it('prints a warning and the customized experimental flags', async () => {
+        if (isTurbopack) {
+          expect(getPreambleOutput(next.cliOutput)).toMatchInlineSnapshot(`
+           "⚠ Prerendering is running in debug mode. Note: This may affect performance and should not be used for production.
+              ▲ Next.js x.y.z (Turbopack)
+              - Experiments (use with caution):
+                ✓ dynamicIO
+                ⨯ turbopackMinify (disabled by \`--debug-prerender\`)
+                ✓ serverSourceMaps (enabled by \`--debug-prerender\`)
+                ⨯ prerenderEarlyExit (disabled by \`--debug-prerender\`)
+                ✓ enablePrerenderSourceMaps (enabled by \`experimental.dynamicIO\`)"
+          `)
+        } else {
+          expect(getPreambleOutput(next.cliOutput)).toMatchInlineSnapshot(`
+           "⚠ Prerendering is running in debug mode. Note: This may affect performance and should not be used for production.
+              ▲ Next.js x.y.z
+              - Experiments (use with caution):
+                ✓ dynamicIO
+                ✓ serverSourceMaps (enabled by \`--debug-prerender\`)
+                ⨯ serverMinification (disabled by \`--debug-prerender\`)
+                ⨯ prerenderEarlyExit (disabled by \`--debug-prerender\`)
+                ✓ enablePrerenderSourceMaps (enabled by \`experimental.dynamicIO\`)"
+          `)
+        }
+      })
+
+      it('shows all prerender errors with readable stacks and code frames', async () => {
+        if (isTurbopack) {
+          expect(getPrerenderOutput(next.cliOutput)).toMatchInlineSnapshot(`
+           "Error: Route "/client" used \`new Date()\` inside a Client Component without a Suspense boundary above it. See more info here: https://nextjs.org/docs/messages/next-prerender-current-time-client
+               at Page (turbopack:///[project]/app/client/page.tsx:4:27)
+             2 |
+             3 | export default function Page() {
+           > 4 |   return <p>Current time: {new Date().toISOString()}</p>
+               |                           ^
+             5 | }
+             6 |
+           To get a more detailed stack trace and pinpoint the issue, start the app in development mode by running \`next dev\`, then open "/client" in your browser to investigate the error.
+           Error occurred prerendering page "/client". Read more: https://nextjs.org/docs/messages/prerender-error
+           Error: Route "/server" used \`Math.random()\` outside of \`"use cache"\` and without explicitly calling \`await connection()\` beforehand. See more info here: https://nextjs.org/docs/messages/next-prerender-random
+               at Page (turbopack:///[project]/app/server/page.tsx:13:26)
+             11 |   await cachedDelay()
+             12 |
+           > 13 |   return <p>Random: {Math.random()}</p>
+                |                          ^
+             14 | }
+             15 |
+           To get a more detailed stack trace and pinpoint the issue, start the app in development mode by running \`next dev\`, then open "/server" in your browser to investigate the error.
+           Error occurred prerendering page "/server". Read more: https://nextjs.org/docs/messages/prerender-error
+
+           > Export encountered errors on following paths:
+           	/client/page: /client
+           	/server/page: /server"
+          `)
+        } else {
+          expect(getPrerenderOutput(next.cliOutput)).toMatchInlineSnapshot(`
+           "Error: Route "/client" used \`new Date()\` inside a Client Component without a Suspense boundary above it. See more info here: https://nextjs.org/docs/messages/next-prerender-current-time-client
+               at Page (webpack:///app/client/page.tsx:4:27)
+             2 |
+             3 | export default function Page() {
+           > 4 |   return <p>Current time: {new Date().toISOString()}</p>
+               |                           ^
+             5 | }
+             6 |
+           To get a more detailed stack trace and pinpoint the issue, start the app in development mode by running \`next dev\`, then open "/client" in your browser to investigate the error.
+           Error occurred prerendering page "/client". Read more: https://nextjs.org/docs/messages/prerender-error
+           Error: Route "/server" used \`Math.random()\` outside of \`"use cache"\` and without explicitly calling \`await connection()\` beforehand. See more info here: https://nextjs.org/docs/messages/next-prerender-random
+               at Page (webpack:///app/server/page.tsx:13:26)
+             11 |   await cachedDelay()
+             12 |
+           > 13 |   return <p>Random: {Math.random()}</p>
+                |                          ^
+             14 | }
+             15 |
+           To get a more detailed stack trace and pinpoint the issue, start the app in development mode by running \`next dev\`, then open "/server" in your browser to investigate the error.
+           Error occurred prerendering page "/server". Read more: https://nextjs.org/docs/messages/prerender-error
+
+           > Export encountered errors on following paths:
+           	/client/page: /client
+           	/server/page: /server"
+          `)
+        }
+      })
     })
   })
 
-  describe('with --debug-prerender', () => {
-    const { next, isTurbopack } = nextTestSetup({
-      files: __dirname,
-      skipStart: true,
-      buildArgs: ['--debug-prerender'],
-    })
+  describe('without a next config file', () => {
+    describe('without --debug-prerender', () => {
+      const { next, isTurbopack } = nextTestSetup({
+        files: path.join(__dirname, 'fixtures/without-config-file'),
+        skipStart: true,
+      })
 
-    beforeAll(() => next.build())
-
-    it('prints a warning and the customized experimental flags', async () => {
-      if (isTurbopack) {
-        expect(getPreambleOutput(next.cliOutput)).toMatchInlineSnapshot(`
-         "⚠ Prerendering is running in debug mode. Note: This may affect performance and should not be used for production.
-            ▲ Next.js x.y.z (Turbopack)
-            - Experiments (use with caution):
-              ✓ dynamicIO
-              ⨯ turbopackMinify (disabled by \`--debug-prerender\`)
-              ✓ serverSourceMaps (enabled by \`--debug-prerender\`)
-              ⨯ prerenderEarlyExit (disabled by \`--debug-prerender\`)
-              ✓ enablePrerenderSourceMaps (enabled by \`experimental.dynamicIO\`)"
-        `)
-      } else {
-        expect(getPreambleOutput(next.cliOutput)).toMatchInlineSnapshot(`
-         "⚠ Prerendering is running in debug mode. Note: This may affect performance and should not be used for production.
-            ▲ Next.js x.y.z
-            - Experiments (use with caution):
-              ✓ dynamicIO
-              ✓ serverSourceMaps (enabled by \`--debug-prerender\`)
-              ⨯ serverMinification (disabled by \`--debug-prerender\`)
-              ⨯ prerenderEarlyExit (disabled by \`--debug-prerender\`)
-              ✓ enablePrerenderSourceMaps (enabled by \`experimental.dynamicIO\`)"
-        `)
-      }
+      beforeAll(() => next.build())
+
+      it('prints no experimental flags', async () => {
+        if (isTurbopack) {
+          expect(getPreambleOutput(next.cliOutput)).toMatchInlineSnapshot(
+            `"▲ Next.js x.y.z (Turbopack)"`
+          )
+        } else {
+          expect(getPreambleOutput(next.cliOutput)).toMatchInlineSnapshot(
+            `"▲ Next.js x.y.z"`
+          )
+        }
+      })
     })
 
-    it('shows all prerender errors with readable stacks and code frames', async () => {
-      if (isTurbopack) {
-        expect(getPrerenderOutput(next.cliOutput)).toMatchInlineSnapshot(`
-         "Error: Route "/client" used \`new Date()\` inside a Client Component without a Suspense boundary above it. See more info here: https://nextjs.org/docs/messages/next-prerender-current-time-client
-             at Page (turbopack:///[project]/app/client/page.tsx:4:27)
-           2 |
-           3 | export default function Page() {
-         > 4 |   return <p>Current time: {new Date().toISOString()}</p>
-             |                           ^
-           5 | }
-           6 |
-         To get a more detailed stack trace and pinpoint the issue, start the app in development mode by running \`next dev\`, then open "/client" in your browser to investigate the error.
-         Error occurred prerendering page "/client". Read more: https://nextjs.org/docs/messages/prerender-error
-         Error: Route "/server" used \`Math.random()\` outside of \`"use cache"\` and without explicitly calling \`await connection()\` beforehand. See more info here: https://nextjs.org/docs/messages/next-prerender-random
-             at Page (turbopack:///[project]/app/server/page.tsx:13:26)
-           11 |   await cachedDelay()
-           12 |
-         > 13 |   return <p>Random: {Math.random()}</p>
-              |                          ^
-           14 | }
-           15 |
-         To get a more detailed stack trace and pinpoint the issue, start the app in development mode by running \`next dev\`, then open "/server" in your browser to investigate the error.
-         Error occurred prerendering page "/server". Read more: https://nextjs.org/docs/messages/prerender-error
-
-         > Export encountered errors on following paths:
-         	/client/page: /client
-         	/server/page: /server"
-        `)
-      } else {
-        expect(getPrerenderOutput(next.cliOutput)).toMatchInlineSnapshot(`
-         "Error: Route "/client" used \`new Date()\` inside a Client Component without a Suspense boundary above it. See more info here: https://nextjs.org/docs/messages/next-prerender-current-time-client
-             at Page (webpack:///app/client/page.tsx:4:27)
-           2 |
-           3 | export default function Page() {
-         > 4 |   return <p>Current time: {new Date().toISOString()}</p>
-             |                           ^
-           5 | }
-           6 |
-         To get a more detailed stack trace and pinpoint the issue, start the app in development mode by running \`next dev\`, then open "/client" in your browser to investigate the error.
-         Error occurred prerendering page "/client". Read more: https://nextjs.org/docs/messages/prerender-error
-         Error: Route "/server" used \`Math.random()\` outside of \`"use cache"\` and without explicitly calling \`await connection()\` beforehand. See more info here: https://nextjs.org/docs/messages/next-prerender-random
-             at Page (webpack:///app/server/page.tsx:13:26)
-           11 |   await cachedDelay()
-           12 |
-         > 13 |   return <p>Random: {Math.random()}</p>
-              |                          ^
-           14 | }
-           15 |
-         To get a more detailed stack trace and pinpoint the issue, start the app in development mode by running \`next dev\`, then open "/server" in your browser to investigate the error.
-         Error occurred prerendering page "/server". Read more: https://nextjs.org/docs/messages/prerender-error
-
-         > Export encountered errors on following paths:
-         	/client/page: /client
-         	/server/page: /server"
-        `)
-      }
+    describe('with --debug-prerender', () => {
+      const { next, isTurbopack } = nextTestSetup({
+        files: path.join(__dirname, 'fixtures/without-config-file'),
+        skipStart: true,
+        buildArgs: ['--debug-prerender'],
+      })
+
+      beforeAll(() => next.build())
+
+      it('prints a warning and the customized experimental flags', async () => {
+        if (isTurbopack) {
+          expect(getPreambleOutput(next.cliOutput)).toMatchInlineSnapshot(`
+           "⚠ Prerendering is running in debug mode. Note: This may affect performance and should not be used for production.
+              ▲ Next.js x.y.z (Turbopack)
+              - Experiments (use with caution):
+                ⨯ turbopackMinify (disabled by \`--debug-prerender\`)
+                ✓ serverSourceMaps (enabled by \`--debug-prerender\`)
+                ⨯ prerenderEarlyExit (disabled by \`--debug-prerender\`)
+                ✓ enablePrerenderSourceMaps (enabled by \`--debug-prerender\`)"
+          `)
+        } else {
+          expect(getPreambleOutput(next.cliOutput)).toMatchInlineSnapshot(`
+           "⚠ Prerendering is running in debug mode. Note: This may affect performance and should not be used for production.
+              ▲ Next.js x.y.z
+              - Experiments (use with caution):
+                ✓ serverSourceMaps (enabled by \`--debug-prerender\`)
+                ⨯ serverMinification (disabled by \`--debug-prerender\`)
+                ⨯ prerenderEarlyExit (disabled by \`--debug-prerender\`)
+                ✓ enablePrerenderSourceMaps (enabled by \`--debug-prerender\`)"
+          `)
+        }
+      })
     })
   })
 })

filename: test/production/app-dir/build-output-prerender/fixtures/without-config-file/app/layout.tsx
patch: @@ -0,0 +1,8 @@
+import { ReactNode } from 'react'
+export default function Root({ children }: { children: ReactNode }) {
+  return (
+    <html>
+      <body>{children}</body>
+    </html>
+  )
+}

filename: test/production/app-dir/build-output-prerender/fixtures/without-config-file/app/page.tsx
patch: @@ -0,0 +1,3 @@
+export default function Page() {
+  return <p>hello world</p>
+}