@nx/next 24.0.0-beta.1 → 24.0.0-beta.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/dist/plugins/component-testing.js +19 -62
  2. package/dist/plugins/with-nx.d.ts +14 -10
  3. package/dist/plugins/with-nx.js +24 -255
  4. package/dist/src/generators/application/application.js +1 -2
  5. package/dist/src/generators/application/files/common/next.config.js__tmpl__ +0 -22
  6. package/dist/src/generators/application/lib/add-e2e.js +5 -6
  7. package/dist/src/generators/application/lib/add-linting.js +0 -1
  8. package/dist/src/generators/application/lib/add-project.js +1 -46
  9. package/dist/src/generators/application/lib/add-vitest.js +0 -1
  10. package/dist/src/generators/application/lib/normalize-options.js +0 -4
  11. package/dist/src/generators/application/schema.d.ts +0 -1
  12. package/dist/src/generators/custom-server/custom-server.js +6 -25
  13. package/dist/src/generators/custom-server/files/server/main.ts__tmpl__ +3 -3
  14. package/dist/src/generators/custom-server/files/tsconfig.server.json__tmpl__ +1 -1
  15. package/dist/src/generators/cypress-component-configuration/cypress-component-configuration.js +1 -14
  16. package/dist/src/generators/cypress-component-configuration/schema.d.ts +0 -1
  17. package/dist/src/generators/init/init.js +14 -28
  18. package/dist/src/generators/init/schema.d.ts +0 -1
  19. package/dist/src/generators/library/lib/add-rollup-server-entry.js +7 -16
  20. package/dist/src/generators/library/lib/normalize-options.js +0 -5
  21. package/dist/src/generators/library/library.js +1 -2
  22. package/dist/src/generators/library/schema.d.ts +0 -1
  23. package/dist/src/migrations/update-24-0-0/finish-inferred-conversion.md +12 -0
  24. package/dist/src/migrations/update-24-0-0/migrate-config-helpers.md +80 -0
  25. package/dist/src/migrations/update-24-0-0/remove-deprecated-executors.d.ts +6 -0
  26. package/dist/src/migrations/update-24-0-0/remove-deprecated-executors.js +18 -0
  27. package/dist/src/migrations/update-24-0-0/remove-deprecated-executors.md +89 -0
  28. package/dist/src/utils/compose-plugins.d.ts +6 -1
  29. package/dist/src/utils/compose-plugins.js +20 -29
  30. package/dist/src/utils/deprecation.d.ts +0 -5
  31. package/dist/src/utils/deprecation.js +9 -31
  32. package/executors.json +1 -12
  33. package/migrations.json +12 -0
  34. package/package.json +13 -13
  35. package/dist/src/executors/build/build.impl.d.ts +0 -5
  36. package/dist/src/executors/build/build.impl.js +0 -154
  37. package/dist/src/executors/build/lib/check-project.d.ts +0 -1
  38. package/dist/src/executors/build/lib/check-project.js +0 -11
  39. package/dist/src/executors/build/lib/create-next-config-file.d.ts +0 -14
  40. package/dist/src/executors/build/lib/create-next-config-file.js +0 -171
  41. package/dist/src/executors/build/lib/update-package-json.d.ts +0 -3
  42. package/dist/src/executors/build/lib/update-package-json.js +0 -31
  43. package/dist/src/executors/build/schema.json +0 -98
  44. package/dist/src/executors/server/custom-server.impl.d.ts +0 -6
  45. package/dist/src/executors/server/custom-server.impl.js +0 -37
  46. package/dist/src/executors/server/schema.json +0 -85
  47. package/dist/src/executors/server/server.impl.d.ts +0 -6
  48. package/dist/src/executors/server/server.impl.js +0 -115
  49. package/dist/src/utils/runtime-version-utils.d.ts +0 -7
  50. package/dist/src/utils/runtime-version-utils.js +0 -28
@@ -15,21 +15,13 @@ async function customServerGenerator(host, options) {
15
15
  const hasPlugin = nxJson.plugins?.some((p) => typeof p === 'string'
16
16
  ? p === '@nx/next/plugin'
17
17
  : p.plugin === '@nx/next/plugin');
18
- if (project.targets?.build?.executor !== '@nx/next:build' && !hasPlugin) {
19
- devkit_1.logger.error(`Project ${options.project} is not a Next.js project. Did you generate it with "nx g @nx/next:app"?`);
18
+ if (!hasPlugin) {
19
+ devkit_1.logger.error(`The "@nx/next/plugin" plugin is not registered in nx.json. Did you generate ${options.project} with "nx g @nx/next:app"?`);
20
20
  return;
21
21
  }
22
22
  // In Nx 18 next artifacts are inside the project root .next/ & dist/ (for custom server)
23
23
  const outputPath = `dist/${project.root}-server`;
24
24
  const root = project.root;
25
- if ((!root ||
26
- !outputPath ||
27
- !project.targets?.build?.configurations?.development ||
28
- !project.targets?.build?.configurations?.production) &&
29
- !hasPlugin) {
30
- devkit_1.logger.error(`Project ${options.project} has invalid config. Did you generate it with "nx g @nx/next:app"?`);
31
- return;
32
- }
33
25
  if (project.targets?.['build-custom-server'] ||
34
26
  project.targets?.['serve-custom-server']) {
35
27
  devkit_1.logger.warn(`Project ${options.project} has custom server targets already: build-custom-server, serve-custom-server. Remove these targets from project and try again.`);
@@ -37,14 +29,11 @@ async function customServerGenerator(host, options) {
37
29
  }
38
30
  // In Nx 18 next artifacts are inside the project root .next/ & dist/ (for custom server)
39
31
  // So we need ensure the mapping is correct from dist to the project root
40
- const projectPathFromDist = hasPlugin
41
- ? `../../${(0, devkit_1.offsetFromRoot)(project.root)}${project.root}`
42
- : `${(0, devkit_1.offsetFromRoot)(`dist/${project.root}`)}${project.root}`;
32
+ const projectPathFromDist = `../../${(0, devkit_1.offsetFromRoot)(project.root)}${project.root}`;
43
33
  const offset = (0, devkit_1.offsetFromRoot)(project.root);
44
34
  const isTsSolution = (0, internal_2.isUsingTsSolutionSetup)(host);
45
35
  (0, devkit_1.generateFiles)(host, (0, path_1.join)(__dirname, 'files'), project.root, {
46
36
  ...options,
47
- hasPlugin,
48
37
  projectPathFromDist,
49
38
  offsetFromRoot: offset,
50
39
  projectRoot: project.root,
@@ -53,17 +42,9 @@ async function customServerGenerator(host, options) {
53
42
  : './tsconfig.json',
54
43
  tmpl: '',
55
44
  });
56
- if (!hasPlugin) {
57
- project.targets.build.dependsOn = ['build-custom-server'];
58
- project.targets.serve.options.customServerTarget = `${options.project}:serve-custom-server`;
59
- project.targets.serve.configurations.development.customServerTarget = `${options.project}:serve-custom-server:development`;
60
- project.targets.serve.configurations.production.customServerTarget = `${options.project}:serve-custom-server:production`;
61
- }
62
- else {
63
- project.targets['build'] = {
64
- dependsOn: ['^build', 'build-custom-server'],
65
- };
66
- }
45
+ project.targets['build'] = {
46
+ dependsOn: ['^build', 'build-custom-server'],
47
+ };
67
48
  project.targets['build-custom-server'] = {
68
49
  executor: options.compiler === 'tsc' ? '@nx/js:tsc' : '@nx/js:swc',
69
50
  defaultConfiguration: 'production',
@@ -11,12 +11,12 @@ import * as path from 'path';
11
11
  import next from 'next';
12
12
 
13
13
  // Next.js server options:
14
- // - The environment variable is set by `@nx/next:server` when running the dev server.
15
- // - The fallback `__dirname` is for production builds.
14
+ // - `NX_NEXT_DIR` overrides the Next.js app directory.
15
+ // - The fallback resolves the app directory from the built server's location.
16
16
  // - Feel free to change this to suit your needs.
17
17
 
18
18
  const dev = process.env.NODE_ENV === 'development';
19
- const dir = process.env.NX_NEXT_DIR || <%- hasPlugin ? `path.join(__dirname, '${projectPathFromDist}')` : `path.join(__dirname, dev ? '..' : '', '${projectPathFromDist}')`; %>
19
+ const dir = process.env.NX_NEXT_DIR || path.join(__dirname, '<%- projectPathFromDist %>');
20
20
 
21
21
  // HTTP Server options:
22
22
  // - Feel free to change this to suit your needs.
@@ -5,7 +5,7 @@
5
5
  "moduleResolution": "nodenext",
6
6
  "noEmit": false,
7
7
  "incremental": true,
8
- <% if(hasPlugin && compiler === 'tsc') { %>
8
+ <% if(compiler === 'tsc') { %>
9
9
  "tsBuildInfoFile": "<%= offsetFromRoot %>tmp/buildcache/<%= projectRoot %>/server",
10
10
  <% } %>
11
11
  "types": [
@@ -10,10 +10,7 @@ const path_1 = require("path");
10
10
  const versions_1 = require("../../utils/versions");
11
11
  const assert_supported_next_version_1 = require("../../utils/assert-supported-next-version");
12
12
  function cypressComponentConfiguration(tree, options) {
13
- return cypressComponentConfigurationInternal(tree, {
14
- addPlugin: false,
15
- ...options,
16
- });
13
+ return cypressComponentConfigurationInternal(tree, options);
17
14
  }
18
15
  async function cypressComponentConfigurationInternal(tree, options) {
19
16
  (0, assert_supported_next_version_1.assertSupportedNextVersion)(tree);
@@ -24,24 +21,14 @@ async function cypressComponentConfigurationInternal(tree, options) {
24
21
  skipFormat: true,
25
22
  framework: 'next',
26
23
  jsx: true,
27
- addPlugin: options.addPlugin,
28
24
  }));
29
25
  const { webpackInitGenerator } = (0, devkit_1.ensurePackage)('@nx/webpack', versions_1.nxVersion);
30
26
  tasks.push(await webpackInitGenerator(tree, {
31
27
  skipFormat: true,
32
- addPlugin: options.addPlugin,
33
28
  }));
34
29
  const { ensureDependencies, } = require('@nx/webpack/internal');
35
30
  tasks.push(ensureDependencies(tree, { compiler: 'swc', uiFramework: 'react' }));
36
31
  const projectConfig = (0, devkit_1.readProjectConfiguration)(tree, options.project);
37
- if (projectConfig.targets?.['component-test']?.executor ===
38
- '@nx/cypress:cypress') {
39
- projectConfig.targets['component-test'].options = {
40
- ...projectConfig.targets['component-test'].options,
41
- skipServe: true,
42
- };
43
- (0, devkit_1.updateProjectConfiguration)(tree, options.project, projectConfig);
44
- }
45
32
  await addFiles(tree, projectConfig, options);
46
33
  if (!options.skipFormat) {
47
34
  await (0, devkit_1.formatFiles)(tree);
@@ -2,5 +2,4 @@ export interface CypressComponentConfigurationGeneratorSchema {
2
2
  project: string;
3
3
  generateTests: boolean;
4
4
  skipFormat?: boolean;
5
- addPlugin?: boolean;
6
5
  }
@@ -33,37 +33,23 @@ async function updateDependencies(host, schema) {
33
33
  return (0, devkit_1.runTasksInSerial)(...tasks);
34
34
  }
35
35
  function nextInitGenerator(tree, schema) {
36
- return nextInitGeneratorInternal(tree, { addPlugin: false, ...schema });
36
+ return nextInitGeneratorInternal(tree, schema);
37
37
  }
38
38
  async function nextInitGeneratorInternal(host, schema) {
39
39
  (0, assert_supported_next_version_1.assertSupportedNextVersion)(host);
40
- const nxJson = (0, devkit_1.readNxJson)(host);
41
- const addPluginDefault = process.env.NX_ADD_PLUGINS !== 'false' &&
42
- nxJson.useInferencePlugins !== false;
43
- schema.addPlugin ??= addPluginDefault;
44
- if (schema.addPlugin) {
45
- const { createNodesV2, } = require('../../plugins/plugin');
46
- await (0, internal_1.addPlugin)(host, await (0, devkit_1.createProjectGraphAsync)(), '@nx/next/plugin', createNodesV2, {
47
- startTargetName: ['start', 'next:start', 'next-start'],
48
- buildTargetName: ['build', 'next:build', 'next-build'],
49
- devTargetName: ['dev', 'next:dev', 'next-dev'],
50
- serveStaticTargetName: [
51
- 'serve-static',
52
- 'next:serve-static',
53
- 'next-serve-static',
54
- ],
55
- buildDepsTargetName: [
56
- 'build-deps',
57
- 'next:build-deps',
58
- 'next-build-deps',
59
- ],
60
- watchDepsTargetName: [
61
- 'watch-deps',
62
- 'next:watch-deps',
63
- 'next-watch-deps',
64
- ],
65
- }, schema.updatePackageScripts);
66
- }
40
+ const { createNodesV2, } = require('../../plugins/plugin');
41
+ await (0, internal_1.addPlugin)(host, await (0, devkit_1.createProjectGraphAsync)(), '@nx/next/plugin', createNodesV2, {
42
+ startTargetName: ['start', 'next:start', 'next-start'],
43
+ buildTargetName: ['build', 'next:build', 'next-build'],
44
+ devTargetName: ['dev', 'next:dev', 'next-dev'],
45
+ serveStaticTargetName: [
46
+ 'serve-static',
47
+ 'next:serve-static',
48
+ 'next-serve-static',
49
+ ],
50
+ buildDepsTargetName: ['build-deps', 'next:build-deps', 'next-build-deps'],
51
+ watchDepsTargetName: ['watch-deps', 'next:watch-deps', 'next-watch-deps'],
52
+ }, schema.updatePackageScripts);
67
53
  (0, add_gitignore_entry_1.addGitIgnoreEntry)(host);
68
54
  let installTask = () => { };
69
55
  if (!schema.skipPackageJson) {
@@ -3,5 +3,4 @@ export interface InitSchema {
3
3
  skipPackageJson?: boolean;
4
4
  keepExistingVersions?: boolean;
5
5
  updatePackageScripts?: boolean;
6
- addPlugin?: boolean;
7
6
  }
@@ -10,22 +10,13 @@ const devkit_1 = require("@nx/devkit");
10
10
  function addRollupServerEntry(tree, options) {
11
11
  const serverEntry = `src/server.${options.js ? 'js' : 'ts'}`;
12
12
  const rollupConfigPath = (0, devkit_1.joinPathFragments)(options.projectRoot, 'rollup.config.cjs');
13
- if (tree.exists(rollupConfigPath)) {
14
- const content = tree.read(rollupConfigPath, 'utf-8');
15
- const updated = content.replace(/^(\s*)main: .*\n/m, (line, indent) => line + `${indent}additionalEntryPoints: ['./${serverEntry}'],\n`);
16
- if (updated === content) {
17
- throw new Error(`Could not add the server entry to ${rollupConfigPath}: "main" option not found.`);
18
- }
19
- tree.write(rollupConfigPath, updated);
20
- return;
13
+ if (!tree.exists(rollupConfigPath)) {
14
+ throw new Error(`Could not add the server entry: ${rollupConfigPath} not found.`);
21
15
  }
22
- const project = (0, devkit_1.readProjectConfiguration)(tree, options.projectName);
23
- const build = project.targets?.build;
24
- if (build?.executor !== '@nx/rollup:rollup') {
25
- throw new Error(`Could not add the server entry to the "build" target of "${options.projectName}": expected the @nx/rollup:rollup executor.`);
16
+ const content = tree.read(rollupConfigPath, 'utf-8');
17
+ const updated = content.replace(/^(\s*)main: .*\n/m, (line, indent) => line + `${indent}additionalEntryPoints: ['./${serverEntry}'],\n`);
18
+ if (updated === content) {
19
+ throw new Error(`Could not add the server entry to ${rollupConfigPath}: "main" option not found.`);
26
20
  }
27
- build.options.additionalEntryPoints = [
28
- (0, devkit_1.joinPathFragments)(options.projectRoot, serverEntry),
29
- ];
30
- (0, devkit_1.updateProjectConfiguration)(tree, options.projectName, project);
21
+ tree.write(rollupConfigPath, updated);
31
22
  }
@@ -1,7 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.normalizeOptions = normalizeOptions;
4
- const devkit_1 = require("@nx/devkit");
5
4
  const internal_1 = require("@nx/devkit/internal");
6
5
  const internal_2 = require("@nx/js/internal");
7
6
  async function normalizeOptions(host, options) {
@@ -12,10 +11,6 @@ async function normalizeOptions(host, options) {
12
11
  directory: options.directory,
13
12
  importPath: options.importPath,
14
13
  });
15
- const nxJson = (0, devkit_1.readNxJson)(host);
16
- const addPlugin = process.env.NX_ADD_PLUGINS !== 'false' &&
17
- nxJson.useInferencePlugins !== false;
18
- options.addPlugin ??= addPlugin;
19
14
  const isUsingTsSolutionConfig = (0, internal_2.isUsingTsSolutionSetup)(host);
20
15
  return {
21
16
  ...options,
@@ -15,7 +15,6 @@ const versions_1 = require("../../utils/versions");
15
15
  const internal_2 = require("@nx/js/internal");
16
16
  async function libraryGenerator(host, rawOptions) {
17
17
  return await libraryGeneratorInternal(host, {
18
- addPlugin: false,
19
18
  useProjectJson: true,
20
19
  ...rawOptions,
21
20
  });
@@ -23,7 +22,7 @@ async function libraryGenerator(host, rawOptions) {
23
22
  async function libraryGeneratorInternal(host, rawOptions) {
24
23
  (0, assert_supported_next_version_1.assertSupportedNextVersion)(host);
25
24
  const tasks = [];
26
- const addTsPlugin = (0, internal_2.shouldConfigureTsSolutionSetup)(host, rawOptions.addPlugin);
25
+ const addTsPlugin = (0, internal_2.shouldConfigureTsSolutionSetup)(host);
27
26
  const jsInitTask = await (0, js_1.initGenerator)(host, {
28
27
  js: rawOptions.js,
29
28
  addTsPlugin,
@@ -29,6 +29,5 @@ export interface Schema {
29
29
  */
30
30
  setParserOptionsProject?: boolean;
31
31
  skipPackageJson?: boolean;
32
- addPlugin?: boolean;
33
32
  useProjectJson?: boolean;
34
33
  }
@@ -0,0 +1,12 @@
1
+ # Replace removed @nx/next executors with inferred tasks
2
+
3
+ Nx 24 removed `@nx/next:build`, `@nx/next:server` (including old `@nrwl` aliases).
4
+
5
+ Before changing anything, check for leftover work: a project target, a package.json target or a `targetDefaults` entry still uses a removed executor, or the advisory context reports a conversion error. If none applies, make no changes and stop. Treat each advisory-context item as pending work.
6
+
7
+ 1. Inspect all affected projects and workspace defaults. Repair config-loading errors first. Do not restore executor registrations or install older Nx packages.
8
+ 2. Move executor options into next.config and Next CLI flags. Preserve webpack callbacks, transpilePackages, workspace libraries, assets, output directory, environment settings and the intended Webpack/Turbopack mode. Build every migrated Next application unless expensive validation was explicitly skipped.
9
+ 3. Register `@nx/next/plugin` with options/includes that preserve custom target names and mixed inferred/explicit projects. Replace remaining removed-executor targets, including those in package.json and filtered targetDefaults. Transfer their behavior before removing obsolete defaults. Preserve configurations, dependencies, cache inputs/outputs and environment behavior. Do not silently delete unsupported options or unrelated targets. Migrate old @nrwl aliases too.
10
+ 4. Run project graph creation with the daemon and graph cache disabled (`NX_DAEMON=false NX_CACHE_PROJECT_GRAPH=false`), using the workspace package manager. Inspect resolved project targets and verify each migrated entrypoint exists and is inferred (a thin alias to an inferred target is acceptable). Resolve graph errors before completing this migration, even if task validation was skipped. Configs must load for subsequent migrations.
11
+ 5. By default run relevant real builds/tests with task cache disabled, including alternate configurations. Honor an existing preference to skip expensive task validation; otherwise offer that option when validation is slow. Skipping expensive tasks never skips conversion or the graph check. Report each skipped task as unverified. Never weaken assertions or change application behavior to make checks pass.
12
+ 6. Report converted projects, graph validation, task results and any skipped checks. Unconverted targets or a broken graph mean the migration is incomplete. Investigate task failures and distinguish missing environment prerequisites from conversion regressions; do not claim a working workspace with unresolved regressions.
@@ -0,0 +1,80 @@
1
+ # Migrate Next.js config helpers
2
+
3
+ Remove `withNx` and `composePlugins` from Next.js configurations. Compatibility
4
+ exports are inert stubs so old imports do not strand graph creation. Helper behavior was removed in Nx 24. Preserve
5
+ application behavior; successful config loading is not proof of equivalence.
6
+
7
+ ## Inspect before changing
8
+
9
+ Find all `next.config.*` files and imported configuration helpers, including
10
+ aliased imports from `@nx/next` and `@nx/next/plugins/with-nx`. Read project targets,
11
+ configuration overrides, package scripts, tsconfigs, and workspace package exports.
12
+ Record the installed Next version and whether each command uses webpack or
13
+ Turbopack. Preserve both; do not switch bundlers or upgrade Next as part of this
14
+ migration. Handle explicit and inferred targets without changing their types. Nx 24
15
+ removed the `@nx/next` build and serve executors, and a separate migration converts
16
+ their targets, so do not add them back.
17
+
18
+ Record existing output locations, build/serve/export commands, and custom behavior.
19
+ Build a baseline before edits if possible; otherwise use an isolated checkout of
20
+ the old lockfile. Do not downgrade the working workspace or silently skip validation.
21
+
22
+ ## Unwrap the configuration
23
+
24
+ Preserve the original export form and Next's config-function contract, including
25
+ phase, defaultConfig, async results, and the order of third-party wrappers. Replace
26
+ Nx composition with direct composition of the remaining wrappers. Inspect wrapper
27
+ APIs rather than assume every wrapper accepts the same arguments or returns an
28
+ object. Do not discard custom webpack callbacks or overwrite other wrappers.
29
+
30
+ Remove the `nx` property from the final Next config only after accounting for every
31
+ option it contains. Merely deleting `withNx` does not migrate those options.
32
+ `@nx/next:convert-to-inferred` does not finish this job: its existing config rewrite
33
+ preserves `withNx` and moves executor options into `nx`.
34
+
35
+ ## Preserve required behavior
36
+
37
+ Test whether each behavior is needed on this workspace's installed Next version
38
+ and existing bundler. Prefer native options. If no native equivalent preserves the
39
+ behavior, inline the necessary implementation in a local, user-owned config helper.
40
+ The user will maintain that code; do not import Nx's deprecated wrapper or private
41
+ implementation as the replacement.
42
+
43
+ - **Workspace libraries:** verify both tsconfig paths and package-manager workspace
44
+ dependencies, including TypeScript/JSX sources and package exports. Add explicit
45
+ `transpilePackages` entries only where required, merging existing entries. Do not
46
+ assume all workspace libraries are transpiled without configuration.
47
+ - **Output paths:** preserve build output and standalone deployment expectations,
48
+ explicit `distDir`, the `outputPath` the removed executor set, and any
49
+ `NX_NEXT_OUTPUT_PATH` behavior. Keep development output compatible with the
50
+ existing bundler. Check Nx's declared cache outputs still cover actual files.
51
+ - **Static export:** preserve `output: 'export'`, the export destination, and the
52
+ commands that serve it. Do not replace a static export with a server deployment.
53
+ - **File replacements/assets:** account for options in both targets and `nx` config.
54
+ Preserve workspace-relative paths, configuration selection, copy destinations,
55
+ and ignores. Use native facilities or inline the required code, then check output.
56
+ - **ESM imports:** test `.js` specifiers pointing to TypeScript sources. Keep or
57
+ inline `extensionAlias` only where the installed webpack setup needs it; do not
58
+ assume a webpack option affects Turbopack.
59
+ - **CSS/SCSS modules:** test imports from shared libraries under the existing
60
+ bundler. Remove obsolete loader patches only after verifying native support.
61
+ - **Babel:** preserve opted-in `babelUpwardRootMode` behavior and custom transforms.
62
+ Inline required webpack behavior if native configuration is insufficient.
63
+ - **Legacy lint behavior:** retain the effective build behavior where supported;
64
+ do not emit removed Next options on versions that reject them.
65
+
66
+ Avoid patches to Next internals when native configuration works. If behavior cannot
67
+ be preserved, describe the exact blocker and ask for a decision rather than silently
68
+ changing the application.
69
+
70
+ ## Acceptance
71
+
72
+ Recreate the graph without its disk cache. Run affected builds without task-cache
73
+ reuse, relevant tests, production startup/static serving, and dev behavior. Check
74
+ shared-library rendering, CSS/SCSS, copied assets, aliases, output locations, and
75
+ configuration-specific behavior against the baseline. Use semantic comparisons
76
+ where generated hashes differ.
77
+
78
+ Search configs and imported helpers for remaining Nx wrappers. Already migrated
79
+ configs should be unchanged. Report evidence and unresolved differences; never
80
+ remove custom behavior or weaken tests to obtain a successful build.
@@ -0,0 +1,6 @@
1
+ import type { Tree } from '@nx/devkit';
2
+ export default function update(tree: Tree): Promise<{
3
+ nextSteps?: string[];
4
+ agentContext?: string[];
5
+ skipAgentic?: boolean;
6
+ }>;
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.default = update;
4
+ const internal_1 = require("@nx/devkit/internal");
5
+ function update(tree) {
6
+ return (0, internal_1.migrateRemovedExecutors)(tree, [
7
+ '@nx/next:build',
8
+ '@nx/next:server',
9
+ '@nrwl/next:build',
10
+ '@nrwl/next:server',
11
+ ], async (tree, options) => {
12
+ const { convertToInferred } = require('../../generators/convert-to-inferred/convert-to-inferred');
13
+ // The callback only prints the options the converter could not carry
14
+ // over; migrateRemovedExecutors discards it.
15
+ const flushLogs = await convertToInferred(tree, options);
16
+ flushLogs();
17
+ });
18
+ }
@@ -0,0 +1,89 @@
1
+ #### Convert `@nx/next` build and server targets to inferred tasks
2
+
3
+ Nx 24 removes the `@nx/next:build` and `@nx/next:server` executors and their `@nrwl` aliases. The migration registers `@nx/next/plugin` in `nx.json` and converts the targets that use those executors to inferred tasks. It moves build options into `next.config.*`. A target with nothing left to override is removed from project configuration. When several projects share the same remaining options, those options move to a `targetDefaults` entry scoped to the plugin. `targetDefaults` entries keyed by a removed executor are removed once no target uses that executor.
4
+
5
+ The migration lists the targets the converter cannot convert safely. In agentic runs, an AI prompt finishes them and validates the project graph.
6
+
7
+ #### Sample code changes
8
+
9
+ ##### Before
10
+
11
+ ```json title="apps/my-app/project.json"
12
+ {
13
+ "name": "my-app",
14
+ "targets": {
15
+ "build": {
16
+ "executor": "@nx/next:build",
17
+ "defaultConfiguration": "production",
18
+ "options": {
19
+ "outputPath": "dist/apps/my-app"
20
+ },
21
+ "configurations": {
22
+ "development": {
23
+ "outputPath": "apps/my-app"
24
+ },
25
+ "production": {}
26
+ }
27
+ },
28
+ "serve": {
29
+ "executor": "@nx/next:server",
30
+ "defaultConfiguration": "development",
31
+ "options": {
32
+ "dev": true,
33
+ "port": 4200
34
+ },
35
+ "configurations": {
36
+ "development": {
37
+ "buildTarget": "my-app:build:development",
38
+ "dev": true
39
+ },
40
+ "production": {
41
+ "buildTarget": "my-app:build:production",
42
+ "dev": false
43
+ }
44
+ }
45
+ }
46
+ }
47
+ }
48
+ ```
49
+
50
+ ##### After
51
+
52
+ ```json title="apps/my-app/project.json"
53
+ {
54
+ "name": "my-app",
55
+ "targets": {
56
+ "build": {
57
+ "configurations": {
58
+ "development": {}
59
+ }
60
+ },
61
+ "serve": {
62
+ "configurations": {
63
+ "development": {},
64
+ "production": {}
65
+ },
66
+ "defaultConfiguration": "development",
67
+ "options": {
68
+ "port": 4200
69
+ }
70
+ }
71
+ }
72
+ }
73
+ ```
74
+
75
+ ```json title="nx.json"
76
+ {
77
+ "plugins": [
78
+ {
79
+ "plugin": "@nx/next/plugin",
80
+ "options": {
81
+ "buildTargetName": "build",
82
+ "devTargetName": "serve",
83
+ "serveStaticTargetName": "serve-static",
84
+ "startTargetName": "start"
85
+ }
86
+ }
87
+ ]
88
+ }
89
+ ```
@@ -1,3 +1,8 @@
1
1
  import type { NextConfig } from 'next';
2
2
  import type { NextConfigFn, NextPlugin, NextPluginThatReturnsConfigFn } from './config';
3
- export declare function composePlugins(...plugins: (NextPlugin | NextPluginThatReturnsConfigFn)[]): (baseConfig: NextConfig) => NextConfigFn;
3
+ /**
4
+ * @deprecated Export the Next.js config directly and compose
5
+ * any other wrappers yourself.
6
+ * This inert stub will be removed in Nx v25.
7
+ */
8
+ export declare function composePlugins(..._plugins: (NextPlugin | NextPluginThatReturnsConfigFn)[]): (baseConfig: NextConfig) => NextConfigFn;
@@ -1,34 +1,25 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.composePlugins = composePlugins;
4
- function composePlugins(...plugins) {
5
- return function (baseConfig) {
6
- return async function combined(phase, context) {
7
- const { PHASE_PRODUCTION_SERVER, } = require('next/constants');
8
- // Copied verbatim into the build output (see create-next-config-file.ts),
9
- // so this must load without @nx/next or @nx/devkit installed. Warn only on
10
- // the active Nx-task path, resolved from the workspace like with-nx.ts.
11
- if (phase !== PHASE_PRODUCTION_SERVER &&
12
- !global.NX_GRAPH_CREATION &&
13
- process.env.NX_TASK_TARGET_TARGET) {
14
- const { workspaceRoot } = require('@nx/devkit');
15
- const { warnComposePluginsDeprecation } = require(require.resolve('@nx/next/src/utils/deprecation', {
16
- paths: [workspaceRoot],
17
- }));
18
- warnComposePluginsDeprecation(phase);
19
- }
20
- let config = baseConfig;
21
- for (const plugin of plugins) {
22
- const fn = await plugin;
23
- const configOrFn = fn(config);
24
- if (typeof configOrFn === 'function') {
25
- config = await configOrFn(phase, context);
26
- }
27
- else {
28
- config = configOrFn;
29
- }
30
- }
31
- return config;
32
- };
4
+ // TODO(v25): remove the inert config-helper stubs in this file.
5
+ /**
6
+ * @deprecated Export the Next.js config directly and compose
7
+ * any other wrappers yourself.
8
+ * This inert stub will be removed in Nx v25.
9
+ */
10
+ function composePlugins(..._plugins) {
11
+ return (baseConfig) => async (phase) => {
12
+ const { PHASE_PRODUCTION_SERVER } = require('next/constants');
13
+ // Copied into production builds, so only resolve the warning on Nx task runs.
14
+ if (phase !== PHASE_PRODUCTION_SERVER &&
15
+ !global.NX_GRAPH_CREATION &&
16
+ process.env.NX_TASK_TARGET_TARGET) {
17
+ const { workspaceRoot } = require('@nx/devkit');
18
+ const { warnComposePluginsDeprecation } = require(require.resolve('@nx/next/src/utils/deprecation', {
19
+ paths: [workspaceRoot],
20
+ }));
21
+ warnComposePluginsDeprecation(phase);
22
+ }
23
+ return baseConfig;
33
24
  };
34
25
  }
@@ -1,11 +1,6 @@
1
1
  declare global {
2
2
  var NX_GRAPH_CREATION: boolean;
3
3
  }
4
- export declare const NEXT_BUILD_EXECUTOR_DEPRECATION_MESSAGE = "The `@nx/next:build` executor is deprecated and will be removed in Nx v24. Run `nx g @nx/next:convert-to-inferred` to migrate to the `@nx/next/plugin` inferred targets. See https://nx.dev/docs/guides/tasks--caching/convert-to-inferred for details.";
5
- export declare const NEXT_SERVER_EXECUTOR_DEPRECATION_MESSAGE = "The `@nx/next:server` executor is deprecated and will be removed in Nx v24. Run `nx g @nx/next:convert-to-inferred` to migrate to the `@nx/next/plugin` inferred targets. See https://nx.dev/docs/guides/tasks--caching/convert-to-inferred for details.";
6
- export declare function warnNextBuildExecutorDeprecation(): void;
7
- export declare function warnNextServerExecutorDeprecation(): void;
8
- export declare function warnNextExecutorGenerating(): void;
9
4
  export declare const WITHNX_DEPRECATION_MESSAGE: string;
10
5
  export declare const COMPOSE_PLUGINS_DEPRECATION_MESSAGE: string;
11
6
  export declare function warnWithNxDeprecation(): void;
@@ -1,39 +1,17 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.COMPOSE_PLUGINS_DEPRECATION_MESSAGE = exports.WITHNX_DEPRECATION_MESSAGE = exports.NEXT_SERVER_EXECUTOR_DEPRECATION_MESSAGE = exports.NEXT_BUILD_EXECUTOR_DEPRECATION_MESSAGE = void 0;
4
- exports.warnNextBuildExecutorDeprecation = warnNextBuildExecutorDeprecation;
5
- exports.warnNextServerExecutorDeprecation = warnNextServerExecutorDeprecation;
6
- exports.warnNextExecutorGenerating = warnNextExecutorGenerating;
3
+ exports.COMPOSE_PLUGINS_DEPRECATION_MESSAGE = exports.WITHNX_DEPRECATION_MESSAGE = void 0;
7
4
  exports.warnWithNxDeprecation = warnWithNxDeprecation;
8
5
  exports.warnComposePluginsDeprecation = warnComposePluginsDeprecation;
9
6
  const devkit_1 = require("@nx/devkit");
10
- // TODO(v24): Remove the @nx/next:build and @nx/next:server executors. The
11
- // inferred plugin (@nx/next/plugin) and the convert-to-inferred generator
12
- // stay supported.
13
- exports.NEXT_BUILD_EXECUTOR_DEPRECATION_MESSAGE = 'The `@nx/next:build` executor is deprecated and will be removed in Nx v24. Run `nx g @nx/next:convert-to-inferred` to migrate to the `@nx/next/plugin` inferred targets. See https://nx.dev/docs/guides/tasks--caching/convert-to-inferred for details.';
14
- exports.NEXT_SERVER_EXECUTOR_DEPRECATION_MESSAGE = 'The `@nx/next:server` executor is deprecated and will be removed in Nx v24. Run `nx g @nx/next:convert-to-inferred` to migrate to the `@nx/next/plugin` inferred targets. See https://nx.dev/docs/guides/tasks--caching/convert-to-inferred for details.';
15
- function warnNextBuildExecutorDeprecation() {
16
- devkit_1.logger.warn(exports.NEXT_BUILD_EXECUTOR_DEPRECATION_MESSAGE);
17
- }
18
- function warnNextServerExecutorDeprecation() {
19
- devkit_1.logger.warn(exports.NEXT_SERVER_EXECUTOR_DEPRECATION_MESSAGE);
20
- }
21
- // Fired when the @nx/next:application generator is about to generate targets
22
- // that use the deprecated executors — i.e. when @nx/next/plugin isn't
23
- // registered in nx.json. Surfaces the deprecation at generation time rather
24
- // than only when the user later runs the generated targets.
25
- function warnNextExecutorGenerating() {
26
- devkit_1.logger.warn('Generating targets that use the deprecated `@nx/next:build` and `@nx/next:server` executors. These executors will be removed in Nx v24. Run `nx g @nx/next:convert-to-inferred` next to migrate these targets to the `@nx/next/plugin` inferred plugin and prevent future generators from emitting executor targets. See https://nx.dev/docs/guides/tasks--caching/convert-to-inferred for details.');
27
- }
28
- // TODO(v24): Remove the `withNx`/`composePlugins` config wrappers. Modern
29
- // workspaces resolve libraries via package manager workspaces and Next.js
30
- // transpiles workspace source automatically, so a plain `next.config.js` works.
31
- exports.WITHNX_DEPRECATION_MESSAGE = '[Nx] `withNx()` from `@nx/next` is deprecated and will be removed in Nx v24. ' +
32
- 'A plain `next.config.js` is now the recommended pattern; Next.js transpiles workspace libraries automatically. ' +
33
- 'See https://nx.dev/docs/technologies/react/next/Guides/next-config-setup for the migration recipe.';
34
- exports.COMPOSE_PLUGINS_DEPRECATION_MESSAGE = '[Nx] `composePlugins()` from `@nx/next` is deprecated and will be removed in Nx v24. ' +
35
- 'Compose Next.js plugins directly in your `next.config.js` and remove the `@nx/next` import. ' +
36
- 'See https://nx.dev/docs/technologies/react/next/Guides/next-config-setup for the migration recipe.';
7
+ // Helper behavior was removed in v24; exports remain only as inert stubs.
8
+ // Keep old configs loadable; preserve required wrapper behavior in user config.
9
+ exports.WITHNX_DEPRECATION_MESSAGE = '[Nx] `withNx()` from `@nx/next` was removed in Nx v24. The remaining export is an inert compatibility stub and does not configure builds. ' +
10
+ 'Migrate to native Next.js configuration and inline any remaining required behavior. ' +
11
+ 'Follow the config-helper migration instructions generated by `nx migrate`.';
12
+ exports.COMPOSE_PLUGINS_DEPRECATION_MESSAGE = '[Nx] `composePlugins()` from `@nx/next` was removed in Nx v24. The remaining export is an inert compatibility stub and does not configure builds. ' +
13
+ 'Compose Next.js plugins directly, preserving their order and config-function behavior. ' +
14
+ 'Follow the config-helper migration instructions generated by `nx migrate`.';
37
15
  let warnedWithNx = false;
38
16
  function warnWithNxDeprecation() {
39
17
  if (warnedWithNx)
package/executors.json CHANGED
@@ -1,14 +1,3 @@
1
1
  {
2
- "executors": {
3
- "build": {
4
- "implementation": "./dist/src/executors/build/build.impl",
5
- "schema": "./dist/src/executors/build/schema.json",
6
- "description": "Build a Next.js application."
7
- },
8
- "server": {
9
- "implementation": "./dist/src/executors/server/server.impl",
10
- "schema": "./dist/src/executors/server/schema.json",
11
- "description": "Serve a Next.js application."
12
- }
13
- }
2
+ "executors": {}
14
3
  }