Repository: vercel/next.js
Pull request: Move `config.turbopack.moduleIds` to `config.experimental.turbopackModuleIds`

https://github.com/vercel/next.js/pull/77850 moved `experimental.turbo` option to `turbopack`, but `moduleIds` is intended for debugging, in line with `turbopackSourceMaps` and `turbopackMinify`, so move to `experimental.turbopackModuleIds`.

- In development, it's "named" by default, and making it "deterministic" breaks HMR.
- In production, it's "deterministic" by default, and making it "named" blows up bundle sizes and exposes your internal project structure in the module ID strings.

Changed files:
filename: crates/next-core/src/next_config.rs
patch: @@ -560,7 +560,6 @@ pub struct TurbopackConfig {
     pub rules: Option<FxIndexMap<RcStr, RuleConfigCollection>>,
     pub resolve_alias: Option<FxIndexMap<RcStr, JsonValue>>,
     pub resolve_extensions: Option<Vec<RcStr>>,
-    pub module_ids: Option<ModuleIds>,
 }
 
 #[derive(
@@ -881,6 +880,7 @@ pub struct ExperimentalConfig {
     worker_threads: Option<bool>,
 
     turbopack_minify: Option<bool>,
+    turbopack_module_ids: Option<ModuleIds>,
     turbopack_persistent_caching: Option<bool>,
     turbopack_source_maps: Option<bool>,
     turbopack_tree_shaking: Option<bool>,
@@ -1807,9 +1807,8 @@ impl NextConfig {
             // Ignore configuration in development mode, HMR only works with `named`
             NextMode::Development => ModuleIds::Named.cell(),
             NextMode::Build => self
-                .turbopack
-                .as_ref()
-                .and_then(|t| t.module_ids)
+                .experimental
+                .turbopack_module_ids
                 .unwrap_or(ModuleIds::Deterministic)
                 .cell(),
         })

filename: docs/01-app/03-api-reference/08-turbopack.mdx
patch: @@ -186,8 +186,6 @@ Turbopack can be configured via `next.config.js` (or `next.config.ts`) under the
   Create manual aliases (like `resolve.alias` in webpack).
 - **`resolveExtensions`**
   Change or extend file extensions for module resolution.
-- **`moduleIds`**
-  Set how module IDs are generated (`'named'` vs `'deterministic'`).
 
 ```js filename="next.config.js"
 module.exports = {

filename: packages/next/src/server/config-schema.ts
patch: @@ -158,7 +158,6 @@ const zTurbopackConfig: zod.ZodType<TurbopackOptions> = z.strictObject({
     )
     .optional(),
   resolveExtensions: z.array(z.string()).optional(),
-  moduleIds: z.enum(['named', 'deterministic']).optional(),
   root: z.string().optional(),
 })
 
@@ -446,6 +445,7 @@ export const configSchema: zod.ZodType<NextConfig> = z.lazy(() =>
         turbopackUseSystemTlsCerts: z.boolean().optional(),
         turbopackUseBuiltinBabel: z.boolean().optional(),
         turbopackUseBuiltinSass: z.boolean().optional(),
+        turbopackModuleIds: z.enum(['named', 'deterministic']).optional(),
         optimizePackageImports: z.array(z.string()).optional(),
         optimizeServerReact: z.boolean().optional(),
         clientTraceMetadata: z.array(z.string()).optional(),

filename: packages/next/src/server/config-shared.ts
patch: @@ -167,13 +167,6 @@ export interface TurbopackOptions {
    */
   rules?: Record<string, TurbopackRuleConfigCollection>
 
-  /**
-   * The module ID strategy to use for Turbopack.
-   * If not set, the default is `'named'` for development and `'deterministic'`
-   * for production.
-   */
-  moduleIds?: 'named' | 'deterministic'
-
   /**
    * This is the repo root usually and only files above this
    * directory can be resolved by turbopack.
@@ -804,6 +797,13 @@ export interface ExperimentalConfig {
    * @default false
    */
   mcpServer?: boolean
+
+  /**
+   * The module ID strategy to use for Turbopack.
+   * If not set, the default is `'named'` for development and `'deterministic'`
+   * for production.
+   */
+  turbopackModuleIds?: 'named' | 'deterministic'
 }
 
 export type ExportPathMap = {