Skip to content

Conversation

bgub
Copy link
Contributor

@bgub bgub commented Aug 27, 2025

What?

This PR removes the ESLint integration from Next.js, including:

  • Removing the next lint command
  • Updating documentation to reflect these changes

Why?

As part of Next.js 16, we're removing the built-in ESLint integration to simplify the codebase and encourage users to use the ESLint CLI directly.

How?

  • Removed the next lint command from the CLI
  • Removed ESLint utility functions and formatters
  • Removed the lint command from the CLI documentation

@ijjk ijjk added created-by: Next.js team PRs by the Next.js team. Documentation Related to Next.js' official documentation. type: next labels Aug 27, 2025
Copy link
Contributor Author

bgub commented Aug 27, 2025

Warning

This pull request is not mergeable via GitHub because a downstack PR is open. Once all requirements are satisfied, merge this PR as a stack on Graphite.
Learn more

This stack of pull requests is managed by Graphite. Learn more about stacking.

@bgub bgub requested review from huozhi, ijjk and ztanner August 27, 2025 23:05
Copy link
Contributor

@vercel vercel bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Additional Comments:

packages/next/src/cli/next-build.ts (lines 97-97):

The build function call passes a lint parameter, but the build function no longer accepts this parameter after the ESLint functionality was removed.

View Details

Analysis

In packages/next/src/cli/next-build.ts on line 97, the build() function is being called with the lint parameter as the 5th argument. However, in packages/next/src/build/index.ts, the runLint = true parameter was removed from the function signature (originally the 4th parameter). This means the lint value is now being passed to what used to be the noMangling parameter, and all subsequent parameters are shifted, causing:

  1. lint (boolean) passed to noMangling parameter (expects boolean, but semantically wrong)
  2. !mangling passed to appDirOnly parameter (expects boolean)
  3. experimentalAppOnly passed to isTurbopack parameter (expects boolean)
  4. isTurbopack passed to experimentalBuildMode parameter (expects string)
  5. experimentalBuildMode passed to traceUploadUrl parameter (expects string | undefined)
  6. traceUploadUrl not passed at all

This will cause runtime errors or incorrect behavior during builds. The fix is to remove the lint parameter from the function call on line 97, since the build function no longer performs linting.

@bgub bgub force-pushed the feat/remove-next-lint branch from 45c57e6 to ff7f56a Compare August 27, 2025 23:19
@bgub bgub changed the base branch from canary to graphite-base/83135 August 27, 2025 23:20
@bgub bgub force-pushed the feat/remove-next-lint branch from ff7f56a to 504a8fe Compare August 27, 2025 23:20
@bgub bgub force-pushed the graphite-base/83135 branch from 8a594ed to 76f1a51 Compare August 27, 2025 23:20
@bgub bgub changed the base branch from graphite-base/83135 to feat/no-lint-in-build August 27, 2025 23:20
@bgub bgub force-pushed the feat/remove-next-lint branch from 504a8fe to 0c092d1 Compare August 27, 2025 23:24
@bgub bgub force-pushed the feat/no-lint-in-build branch from 76f1a51 to 0a90014 Compare August 27, 2025 23:24
@ijjk
Copy link
Member

ijjk commented Aug 27, 2025

Failing test suites

Commit: 0c092d1

pnpm test test/integration/eslint/test/lint-cache.test.js (turbopack)

  • eslint caching is enabled by default

  • eslint caching is disabled with the --no-cache flag

  • the default eslint cache lives in the user defined build directory

  • the --cache-location flag allows the user to define a separate cache location

  • the default eslint caching strategy is metadata

  • cache with content strategy is different from the one with default strategy

Expand output

● eslint caching is enabled by default

command failed with code 1 signal null
Invalid project directory provided, no such directory: /root/actions-runner/_work/next.js/next.js/packages/next/lint

  314 |       ) {
  315 |         return reject(
> 316 |           new Error(
      |           ^
  317 |             `command failed with code ${code} signal ${signal}\n${mergedStdio}`
  318 |           )
  319 |         )

  at ChildProcess.<anonymous> (lib/next-test-utils.ts:316:11)

● eslint caching is disabled with the --no-cache flag

command failed with code 1 signal null
error: unknown option '--no-cache'

  314 |       ) {
  315 |         return reject(
> 316 |           new Error(
      |           ^
  317 |             `command failed with code ${code} signal ${signal}\n${mergedStdio}`
  318 |           )
  319 |         )

  at ChildProcess.<anonymous> (lib/next-test-utils.ts:316:11)

● the default eslint cache lives in the user defined build directory

command failed with code 1 signal null
Invalid project directory provided, no such directory: /root/actions-runner/_work/next.js/next.js/packages/next/lint

  314 |       ) {
  315 |         return reject(
> 316 |           new Error(
      |           ^
  317 |             `command failed with code ${code} signal ${signal}\n${mergedStdio}`
  318 |           )
  319 |         )

  at ChildProcess.<anonymous> (lib/next-test-utils.ts:316:11)

● the --cache-location flag allows the user to define a separate cache location

command failed with code 1 signal null
error: unknown option '--cache-location'

  314 |       ) {
  315 |         return reject(
> 316 |           new Error(
      |           ^
  317 |             `command failed with code ${code} signal ${signal}\n${mergedStdio}`
  318 |           )
  319 |         )

  at ChildProcess.<anonymous> (lib/next-test-utils.ts:316:11)

● the default eslint caching strategy is metadata

command failed with code 1 signal null
Invalid project directory provided, no such directory: /root/actions-runner/_work/next.js/next.js/packages/next/lint

  314 |       ) {
  315 |         return reject(
> 316 |           new Error(
      |           ^
  317 |             `command failed with code ${code} signal ${signal}\n${mergedStdio}`
  318 |           )
  319 |         )

  at ChildProcess.<anonymous> (lib/next-test-utils.ts:316:11)

● cache with content strategy is different from the one with default strategy

command failed with code 1 signal null
Invalid project directory provided, no such directory: /root/actions-runner/_work/next.js/next.js/packages/next/lint

  314 |       ) {
  315 |         return reject(
> 316 |           new Error(
      |           ^
  317 |             `command failed with code ${code} signal ${signal}\n${mergedStdio}`
  318 |           )
  319 |         )

  at ChildProcess.<anonymous> (lib/next-test-utils.ts:316:11)

Read more about building and testing Next.js in contributing.md.

pnpm test test/integration/eslint/test/next-lint.test.js (turbopack)

  • Next Lint > should generate next-env.d.ts before lint command
  • Next Lint > shows warnings and errors
  • Next Lint > verify options name and type with auto-generated help output
  • Next Lint > base directories are linted by default
  • Next Lint > shows warnings and errors with next/core-web-vitals config
  • Next Lint > shows warnings and errors when extending plugin recommended config
  • Next Lint > shows warnings and errors when extending plugin core-web-vitals config
  • Next Lint > success message when no warnings or errors
  • Next Lint > quiet flag suppresses warnings and only reports errors
  • Next Lint > custom directories
  • Next Lint > max warnings flag errors when warnings exceed threshold
  • Next Lint > max warnings flag does not error when warnings do not exceed threshold
  • Next Lint > format flag supports additional user-defined formats
  • Next Lint > format flag supports async formatters
  • Next Lint > file flag can selectively lint only a single file
  • Next Lint > file flag can selectively lints multiple files
  • Next Lint > format flag "json" creates a file respecting the chosen format
  • Next Lint > lint files with cjs and mjs file extension
  • Next Lint > First Time Setup > show a prompt to set up ESLint if no configuration detected
  • Next Lint > First Time Setup > installs eslint and eslint-config-next as devDependencies if missing with yarn
  • Next Lint > First Time Setup > installs eslint and eslint-config-next as devDependencies if missing with pnpm
  • Next Lint > First Time Setup > installs eslint and eslint-config-next as devDependencies if missing with npm
  • Next Lint > First Time Setup > creates .eslintrc.json file with a default configuration
  • Next Lint > First Time Setup > creates .eslintrc.json file with a default app router configuration
  • Next Lint > First Time Setup > shows a successful message when completed
Expand output

● Next Lint › First Time Setup › show a prompt to set up ESLint if no configuration detected

expect(received).toContain(expected) // indexOf

Expected substring: "How would you like to configure ESLint?"
Received string:    "Invalid project directory provided, no such directory: /root/actions-runner/_work/next.js/next.js/packages/next/lint
"

  69 |       })
  70 |       const output = stdout + stderr
> 71 |       expect(output).toContain('How would you like to configure ESLint?')
     |                      ^
  72 |
  73 |       // Different options that can be selected
  74 |       expect(output).toContain('Strict (recommended)')

  at Object.toContain (integration/eslint/test/next-lint.test.js:71:22)

● Next Lint › First Time Setup › installs eslint and eslint-config-next as devDependencies if missing with yarn

ENOENT: no such file or directory, open '/tmp/6v35eb2mn8/package.json'

● Next Lint › First Time Setup › installs eslint and eslint-config-next as devDependencies if missing with pnpm

ENOENT: no such file or directory, open '/tmp/op53clhin7/package.json'

● Next Lint › First Time Setup › installs eslint and eslint-config-next as devDependencies if missing with npm

ENOENT: no such file or directory, open '/tmp/nuoplxlfij/package.json'

● Next Lint › First Time Setup › creates .eslintrc.json file with a default configuration

ENOENT: no such file or directory, open '/tmp/tpxmbi1435/package.json'

● Next Lint › First Time Setup › creates .eslintrc.json file with a default app router configuration

ENOENT: no such file or directory, open '/tmp/g4dukkglels/package.json'

● Next Lint › First Time Setup › shows a successful message when completed

ENOENT: no such file or directory, open '/tmp/3dprns9v0xo/package.json'

● Next Lint › should generate next-env.d.ts before lint command

expect(received).toContain(expected) // indexOf

Expected value: "next-env.d.ts"
Received array: [".eslintrc", ".gitignore", "app", "next.config.js", "pages", "tsconfig.json"]

  158 |     const files = await fs.readdir(dirTypescript)
  159 |
> 160 |     expect(files).toContain('next-env.d.ts')
      |                   ^
  161 |   })
  162 |
  163 |   for (const { dir } of [

  at Object.toContain (integration/eslint/test/next-lint.test.js:160:19)

● Next Lint › shows warnings and errors

expect(received).toContain(expected) // indexOf

Expected substring: "Warning: Synchronous scripts should not be used."
Received string:    "Invalid project directory provided, no such directory: /root/actions-runner/_work/next.js/next.js/packages/next/lint
"

  201 |
  202 |     const output = stdout + stderr
> 203 |     expect(output).toContain('Warning: Synchronous scripts should not be used.')
      |                    ^
  204 |     expect(output).toContain(
  205 |       'Error: Comments inside children section of tag should be placed inside braces'
  206 |     )

  at Object.toContain (integration/eslint/test/next-lint.test.js:203:20)

● Next Lint › verify options name and type with auto-generated help output

expect(received).toContain(expected) // indexOf

Expected substring: "-d, --dir, <dirs...>"
Received string:    "Usage: next [options] [command]·
The Next.js CLI allows you to develop, build, start your application, and more.·
Options:
  -v, --version                            Outputs the Next.js version.
  -h, --help                               Displays this message.·
Commands:
  build [directory] [options]              Creates an optimized production build of your application. The output displays information about each route.
  dev [directory] [options]                Starts Next.js in development mode with hot-code reloading, error reporting, and more.
  info [options]                           Prints relevant details about the current system which can be used to report Next.js bugs.
  start [directory] [options]              Starts Next.js in production mode. The application should be compiled with `next build` first.
  telemetry [options] [arg]                Allows you to enable or disable Next.js' completely anonymous telemetry collection.
  typegen [directory] [options]            Generate TypeScript definitions for routes, pages, and layouts without running a full build.
  experimental-test [directory] [options]  Execute `next/experimental/testmode` tests using a specified test runner. The test runner defaults to 'playwright' if the `experimental.defaultTestRunner` configuration option or the `--test-runner` option are not set.
  internal [options] [command]             Internal debugging commands. Use with caution. Not covered by semver.
"

  239 |
  240 |     for (let option of options) {
> 241 |       expect(output).toContain(option)
      |                      ^
  242 |     }
  243 |   })
  244 |

  at Object.toContain (integration/eslint/test/next-lint.test.js:241:22)

● Next Lint › base directories are linted by default

expect(received).toContain(expected) // indexOf

Expected substring: "Error: `next/head` should not be imported in `pages/_document.js`. Use `<Head />` from `next/document` instead"
Received string:    "Invalid project directory provided, no such directory: /root/actions-runner/_work/next.js/next.js/packages/next/lint
"

  250 |
  251 |     const output = stdout + stderr
> 252 |     expect(output).toContain(
      |                    ^
  253 |       'Error: `next/head` should not be imported in `pages/_document.js`. Use `<Head />` from `next/document` instead'
  254 |     )
  255 |     expect(output).toContain(

  at Object.toContain (integration/eslint/test/next-lint.test.js:252:20)

● Next Lint › shows warnings and errors with next/core-web-vitals config

expect(received).toContain(expected) // indexOf

Expected substring: "Warning: Using `<img>` could result in slower LCP and higher bandwidth. Consider using `<Image />` from `next/image` or a custom image loader to automatically optimize images."
Received string:    "Invalid project directory provided, no such directory: /root/actions-runner/_work/next.js/next.js/packages/next/lint
"

  277 |
  278 |     const output = stdout + stderr
> 279 |     expect(output).toContain(
      |                    ^
  280 |       'Warning: Using `<img>` could result in slower LCP and higher bandwidth. Consider using `<Image />` from `next/image` or a custom image loader to automatically optimize images.'
  281 |     )
  282 |     expect(output).toContain('Error: Synchronous scripts should not be used.')

  at Object.toContain (integration/eslint/test/next-lint.test.js:279:20)

● Next Lint › shows warnings and errors when extending plugin recommended config

expect(received).toContain(expected) // indexOf

Expected substring: "Warning: Synchronous scripts should not be used."
Received string:    "Invalid project directory provided, no such directory: /root/actions-runner/_work/next.js/next.js/packages/next/lint
"

  290 |
  291 |     const output = stdout + stderr
> 292 |     expect(output).toContain('Warning: Synchronous scripts should not be used.')
      |                    ^
  293 |     expect(output).toContain(
  294 |       'Error: `<Document />` from `next/document` should not be imported outside of `pages/_document.js`.'
  295 |     )

  at Object.toContain (integration/eslint/test/next-lint.test.js:292:20)

● Next Lint › shows warnings and errors when extending plugin core-web-vitals config

expect(received).toContain(expected) // indexOf

Expected substring: "Warning: Using `<img>` could result in slower LCP and higher bandwidth. Consider using `<Image />` from `next/image` or a custom image loader to automatically optimize images."
Received string:    "Invalid project directory provided, no such directory: /root/actions-runner/_work/next.js/next.js/packages/next/lint
"

  307 |
  308 |     const output = stdout + stderr
> 309 |     expect(output).toContain(
      |                    ^
  310 |       'Warning: Using `<img>` could result in slower LCP and higher bandwidth. Consider using `<Image />` from `next/image` or a custom image loader to automatically optimize images.'
  311 |     )
  312 |     expect(output).toContain('Error: Synchronous scripts should not be used.')

  at Object.toContain (integration/eslint/test/next-lint.test.js:309:20)

● Next Lint › success message when no warnings or errors

expect(received).toContain(expected) // indexOf

Expected substring: "No ESLint warnings or errors"
Received string:    "Invalid project directory provided, no such directory: /root/actions-runner/_work/next.js/next.js/packages/next/lint
"

  323 |
  324 |     const output = stdout + stderr
> 325 |     expect(output).toContain('No ESLint warnings or errors')
      |                    ^
  326 |   })
  327 |
  328 |   test("don't create .eslintrc file if package.json has eslintConfig field", async () => {

  at Object.toContain (integration/eslint/test/next-lint.test.js:325:20)

● Next Lint › quiet flag suppresses warnings and only reports errors

expect(received).toContain(expected) // indexOf

Expected substring: "Error: Comments inside children section of tag should be placed inside braces"
Received string:    "error: unknown option '--quiet'
"

  372 |
  373 |     const output = stdout + stderr
> 374 |     expect(output).toContain(
      |                    ^
  375 |       'Error: Comments inside children section of tag should be placed inside braces'
  376 |     )
  377 |     expect(output).not.toContain(

  at Object.toContain (integration/eslint/test/next-lint.test.js:374:20)

● Next Lint › custom directories

expect(received).toContain(expected) // indexOf

Expected substring: "Error: Comments inside children section of tag should be placed inside braces"
Received string:    "Invalid project directory provided, no such directory: /root/actions-runner/_work/next.js/next.js/packages/next/lint
"

  387 |
  388 |     const output = stdout + stderr
> 389 |     expect(output).toContain(
      |                    ^
  390 |       'Error: Comments inside children section of tag should be placed inside braces'
  391 |     )
  392 |     expect(output).toContain('Warning: Synchronous scripts should not be used.')

  at Object.toContain (integration/eslint/test/next-lint.test.js:389:20)

● Next Lint › max warnings flag errors when warnings exceed threshold

expect(received).toContain(expected) // indexOf

Expected substring: "Warning: Synchronous scripts should not be used."
Received string:    "error: unknown option '--max-warnings'
"

  404 |
  405 |     expect(stderr).not.toEqual('')
> 406 |     expect(stderr).toContain('Warning: Synchronous scripts should not be used.')
      |                    ^
  407 |     expect(stdout).not.toContain(
  408 |       'Warning: Synchronous scripts should not be used.'
  409 |     )

  at Object.toContain (integration/eslint/test/next-lint.test.js:406:20)

● Next Lint › max warnings flag does not error when warnings do not exceed threshold

expect(received).toContain(expected) // indexOf

Expected substring: "Warning: Synchronous scripts should not be used."
Received string:    ""

  423 |       'Warning: Synchronous scripts should not be used.'
  424 |     )
> 425 |     expect(stdout).toContain('Warning: Synchronous scripts should not be used.')
      |                    ^
  426 |   })
  427 |
  428 |   test('format flag supports additional user-defined formats', async () => {

  at Object.toContain (integration/eslint/test/next-lint.test.js:425:20)

● Next Lint › format flag supports additional user-defined formats

expect(received).toContain(expected) // indexOf

Expected substring: "warning: Synchronous scripts should not be used."
Received string:    "error: unknown option '-f'
"

  437 |
  438 |     const output = stdout + stderr
> 439 |     expect(output).toContain('warning: Synchronous scripts should not be used.')
      |                    ^
  440 |     expect(stdout).toContain('<script src="https://example.com" />')
  441 |     expect(stdout).toContain('2 warnings found')
  442 |   })

  at Object.toContain (integration/eslint/test/next-lint.test.js:439:20)

● Next Lint › format flag supports async formatters

expect(received).toContain(expected) // indexOf

Expected substring: "Async results:"
Received string:    "error: unknown option '-f'
"

  453 |
  454 |     const output = stdout + stderr
> 455 |     expect(output).toContain('Async results:')
      |                    ^
  456 |     expect(stdout).toContain('Synchronous scripts should not be used.')
  457 |   })
  458 |

  at Object.toContain (integration/eslint/test/next-lint.test.js:455:20)

● Next Lint › file flag can selectively lint only a single file

expect(received).toContain(expected) // indexOf

Expected substring: "utils/math.js"
Received string:    "error: unknown option '--file'
"

  469 |     const output = stdout + stderr
  470 |
> 471 |     expect(output).toContain('utils/math.js')
      |                    ^
  472 |     expect(output).toContain(
  473 |       'Comments inside children section of tag should be placed inside braces'
  474 |     )

  at Object.toContain (integration/eslint/test/next-lint.test.js:471:20)

● Next Lint › file flag can selectively lints multiple files

expect(received).toContain(expected) // indexOf

Expected substring: "utils/math.js"
Received string:    "error: unknown option '--file'
"

  490 |     const output = stdout + stderr
  491 |
> 492 |     expect(output).toContain('utils/math.js')
      |                    ^
  493 |     expect(output).toContain(
  494 |       'Comments inside children section of tag should be placed inside braces'
  495 |     )

  at Object.toContain (integration/eslint/test/next-lint.test.js:492:20)

● Next Lint › format flag "json" creates a file respecting the chosen format

ENOENT: no such file or directory, open '/root/actions-runner/_work/next.js/next.js/test/integration/eslint/test/output/output.json'

● Next Lint › lint files with cjs and mjs file extension

expect(received).toContain(expected) // indexOf

Expected substring: "pages/bar.mjs"
Received string:    "Invalid project directory provided, no such directory: /root/actions-runner/_work/next.js/next.js/packages/next/lint
"

  564 |     const output = stdout + stderr
  565 |
> 566 |     expect(output).toContain('pages/bar.mjs')
      |                    ^
  567 |     expect(output).toContain(
  568 |       'img elements must have an alt prop, either with meaningful text, or an empty string for decorative images.'
  569 |     )

  at Object.toContain (integration/eslint/test/next-lint.test.js:566:20)

Read more about building and testing Next.js in contributing.md.

pnpm test-dev-turbo test/development/next-lint-eslint-formatter-compact/index.test.ts (turbopack)

  • next-lint-eslint-formatter-compact > should format flag "compact" creates a file respecting the chosen format
  • next-lint-eslint-formatter-compact > should show error message when the file path is a directory
Expand output

● next-lint-eslint-formatter-compact › should format flag "compact" creates a file respecting the chosen format

ENOENT: no such file or directory, open '/tmp/next-install-c5f7a9646aeae40726392701317e22b6c99938ba02ff784d0db72f257b7b1748/output/output.txt'

  21 |
  22 |     const cliOutput = stdout + stderr
> 23 |     const fileOutput = readFileSync(filePath, 'utf8')
     |                                    ^
  24 |
  25 |     expect(cliOutput).toContain(`The output file has been created: ${filePath}`)
  26 |

  at Object.<anonymous> (development/next-lint-eslint-formatter-compact/index.test.ts:23:36)

● next-lint-eslint-formatter-compact › should show error message when the file path is a directory

expect(received).toContain(expected) // indexOf

Expected substring: "Cannot write to output file path, it is a directory: /tmp/next-install-c5f7a9646aeae40726392701317e22b6c99938ba02ff784d0db72f257b7b1748"
Received string:    "error: unknown option '--format'
(Did you mean --port?)
"

  52 |     const cliOutput = stdout + stderr
  53 |     console.log({ cliOutput })
> 54 |     expect(cliOutput).toContain(
     |                       ^
  55 |       `Cannot write to output file path, it is a directory: ${filePath}`
  56 |     )
  57 |   })

  at Object.toContain (development/next-lint-eslint-formatter-compact/index.test.ts:54:23)

Read more about building and testing Next.js in contributing.md.

pnpm test test/integration/eslint/test/next-build.test.js (turbopack)

  • Next Build > production mode > shows warnings and errors
  • Next Build > production mode > base directories are linted by default during builds
  • Next Build > production mode > custom directories
  • Next Build > production mode > invalid older eslint version
  • Next Build > production mode > empty directories do not fail the build
  • Next Build > production mode > eslint ignored directories do not fail the build
  • Next Build > production mode > missing Next.js plugin
  • Next Build > production mode > eslint caching is enabled
  • Next Build > production mode > eslint cache lives in the user defined build directory
Expand output

● Next Build › production mode › shows warnings and errors

expect(received).toContain(expected) // indexOf

Expected substring: "Warning: Synchronous scripts should not be used."
Received string:    "   ▲ Next.js 15.5.1-canary.13 (Turbopack)·
   Checking validity of types ...
   Creating an optimized production build ...
 ✓ Finished writing to disk in 3ms
 ✓ Compiled successfully in 876ms
   Collecting page data ...
   Generating static pages (0/3) ...
 ✓ Generating static pages (3/3)
   Finalizing page optimization ...
   Collecting build traces ...·
Route (pages)                       Size  First Load JS
┌ ○ /                            9.17 kB         107 kB
└ ○ /404                         10.9 kB         109 kB
+ First Load JS shared by all      98 kB
  ├ chunks/a4809e093c77da73.js   88.8 kB
  └ other shared chunks (total)  9.25 kB·
○  (Static)  prerendered as static content·
"

  31 |
  32 |         const output = stdout + stderr
> 33 |         expect(output).toContain(
     |                        ^
  34 |           'Warning: Synchronous scripts should not be used.'
  35 |         )
  36 |         expect(output).toContain(

  at Object.toContain (integration/eslint/test/next-build.test.js:33:24)

● Next Build › production mode › base directories are linted by default during builds

expect(received).toContain(expected) // indexOf

Expected substring: "Failed to compile"
Received string:    "   ▲ Next.js 15.5.1-canary.13 (Turbopack)·
   Creating an optimized production build ...
 ✓ Finished writing to disk in 2ms
 ✓ Compiled successfully in 1322ms
   Checking validity of types ...
   Collecting page data ...
   Generating static pages (0/2) ...
 ✓ Generating static pages (2/2)
   Finalizing page optimization ...
   Collecting build traces ...·
Route (pages)                       Size  First Load JS
─ ○ /404                         10.9 kB         109 kB
+ First Load JS shared by all    98.2 kB
  ├ chunks/07f1a43510118c36.js   88.9 kB
  └ other shared chunks (total)  9.27 kB·
○  (Static)  prerendered as static content·
"

  62 |         const output = stdout + stderr
  63 |
> 64 |         expect(output).toContain('Failed to compile')
     |                        ^
  65 |         expect(output).toContain(
  66 |           'Error: `next/head` should not be imported in `pages/_document.js`. Use `<Head />` from `next/document` instead'
  67 |         )

  at Object.toContain (integration/eslint/test/next-build.test.js:64:24)

● Next Build › production mode › custom directories

expect(received).toContain(expected) // indexOf

Expected substring: "Failed to compile"
Received string:    "   ▲ Next.js 15.5.1-canary.13 (Turbopack)·
   Checking validity of types ...
   Creating an optimized production build ...
 ✓ Finished writing to disk in 2ms
 ✓ Compiled successfully in 879ms
   Collecting page data ...
   Generating static pages (0/3) ...
 ✓ Generating static pages (3/3)
   Finalizing page optimization ...
   Collecting build traces ...·
Route (pages)                       Size  First Load JS
┌ ○ /                            9.15 kB         107 kB
└ ○ /404                         10.9 kB         109 kB
+ First Load JS shared by all      98 kB
  ├ chunks/a4809e093c77da73.js   88.8 kB
  └ other shared chunks (total)  9.25 kB·
○  (Static)  prerendered as static content·
"

  93 |
  94 |         const output = stdout + stderr
> 95 |         expect(output).toContain('Failed to compile')
     |                        ^
  96 |         expect(output).toContain(
  97 |           'Error: Comments inside children section of tag should be placed inside braces'
  98 |         )

  at Object.toContain (integration/eslint/test/next-build.test.js:95:24)

● Next Build › production mode › invalid older eslint version

expect(received).toContain(expected) // indexOf

Expected substring: "Your project has an older version of ESLint installed"
Received string:    "   ▲ Next.js 15.5.1-canary.13 (Turbopack)·
   Checking validity of types ...
   Creating an optimized production build ...
 ✓ Finished writing to disk in 2ms
 ✓ Compiled successfully in 871ms
   Collecting page data ...
   Generating static pages (0/3) ...
 ✓ Generating static pages (3/3)
   Finalizing page optimization ...
   Collecting build traces ...·
Route (pages)                       Size  First Load JS
┌ ○ /                            9.14 kB         107 kB
└ ○ /404                         10.9 kB         109 kB
+ First Load JS shared by all      98 kB
  ├ chunks/a4809e093c77da73.js   88.8 kB
  └ other shared chunks (total)  9.25 kB·
○  (Static)  prerendered as static content·
"

  114 |
  115 |         const output = stdout + stderr
> 116 |         expect(output).toContain(
      |                        ^
  117 |           'Your project has an older version of ESLint installed'
  118 |         )
  119 |       })

  at Object.toContain (integration/eslint/test/next-build.test.js:116:24)

● Next Build › production mode › empty directories do not fail the build

expect(received).toContain(expected) // indexOf

Expected substring: "Warning: Synchronous scripts should not be used."
Received string:    "   ▲ Next.js 15.5.1-canary.13 (Turbopack)·
   Checking validity of types ...
   Creating an optimized production build ...
 ✓ Finished writing to disk in 2ms
 ✓ Compiled successfully in 902ms
   Collecting page data ...
   Generating static pages (0/3) ...
 ✓ Generating static pages (3/3)
   Finalizing page optimization ...
   Collecting build traces ...·
Route (pages)                       Size  First Load JS
┌ ○ /                            9.15 kB         107 kB
└ ○ /404                         10.9 kB         109 kB
+ First Load JS shared by all      98 kB
  ├ chunks/a4809e093c77da73.js   88.8 kB
  └ other shared chunks (total)  9.25 kB·
○  (Static)  prerendered as static content·
"

  129 |         expect(output).not.toContain('Build error occurred')
  130 |         expect(output).not.toContain('NoFilesFoundError')
> 131 |         expect(output).toContain(
      |                        ^
  132 |           'Warning: Synchronous scripts should not be used.'
  133 |         )
  134 |         expect(output).toContain('Compiled successfully')

  at Object.toContain (integration/eslint/test/next-build.test.js:131:24)

● Next Build › production mode › eslint ignored directories do not fail the build

expect(received).toContain(expected) // indexOf

Expected substring: "Warning: Synchronous scripts should not be used."
Received string:    "   ▲ Next.js 15.5.1-canary.13 (Turbopack)·
   Checking validity of types ...
   Creating an optimized production build ...
 ✓ Finished writing to disk in 2ms
 ✓ Compiled successfully in 889ms
   Collecting page data ...
   Generating static pages (0/3) ...
 ✓ Generating static pages (3/3)
   Finalizing page optimization ...
   Collecting build traces ...·
Route (pages)                       Size  First Load JS
┌ ○ /                            9.16 kB         107 kB
└ ○ /404                         10.9 kB         109 kB
+ First Load JS shared by all      98 kB
  ├ chunks/a4809e093c77da73.js   88.8 kB
  └ other shared chunks (total)  9.25 kB·
○  (Static)  prerendered as static content·
"

  145 |         expect(output).not.toContain('Build error occurred')
  146 |         expect(output).not.toContain('AllFilesIgnoredError')
> 147 |         expect(output).toContain(
      |                        ^
  148 |           'Warning: Synchronous scripts should not be used.'
  149 |         )
  150 |         expect(output).toContain('Compiled successfully')

  at Object.toContain (integration/eslint/test/next-build.test.js:147:24)

● Next Build › production mode › missing Next.js plugin

expect(received).toContain(expected) // indexOf

Expected substring: "The Next.js plugin was not detected in your ESLint configuration"
Received string:    "   ▲ Next.js 15.5.1-canary.13 (Turbopack)·
   Checking validity of types ...
   Creating an optimized production build ...
 ✓ Finished writing to disk in 2ms
 ✓ Compiled successfully in 880ms
   Collecting page data ...
   Generating static pages (0/3) ...
 ✓ Generating static pages (3/3)
   Finalizing page optimization ...
   Collecting build traces ...·
Route (pages)                       Size  First Load JS
┌ ○ /                            9.12 kB         107 kB
└ ○ /404                         10.9 kB         109 kB
+ First Load JS shared by all      98 kB
  ├ chunks/a4809e093c77da73.js   88.8 kB
  └ other shared chunks (total)  9.25 kB·
○  (Static)  prerendered as static content·
"

  159 |
  160 |         const output = stdout + stderr
> 161 |         expect(output).toContain(
      |                        ^
  162 |           'The Next.js plugin was not detected in your ESLint configuration'
  163 |         )
  164 |       })

  at Object.toContain (integration/eslint/test/next-build.test.js:161:24)

● Next Build › production mode › eslint caching is enabled

ENOENT: no such file or directory, scandir '/root/actions-runner/_work/next.js/next.js/test/integration/eslint/eslint-cache/.next/cache/eslint/'

● Next Build › production mode › eslint cache lives in the user defined build directory

ENOENT: no such file or directory, scandir '/root/actions-runner/_work/next.js/next.js/test/integration/eslint/eslint-cache-custom-dir/build/cache/eslint/'

Read more about building and testing Next.js in contributing.md.

pnpm test-start-turbo test/production/eslint-plugin-deps/index.test.ts (turbopack)

  • eslint plugin deps > should work
Expand output

● eslint plugin deps › should work

next build failed with code/signal 1

  107 |             if (code || signal)
  108 |               reject(
> 109 |                 new Error(
      |                 ^
  110 |                   `next build failed with code/signal ${code || signal}`
  111 |                 )
  112 |               )

  at ChildProcess.<anonymous> (lib/next-modes/next-start.ts:109:17)

● Test suite failed to run

TypeError: Cannot read properties of undefined (reading 'destroy')

  147 |     })
  148 |   })
> 149 |   afterAll(() => next.destroy())
      |                       ^
  150 |
  151 |   it('should work', async () => {
  152 |     const html = await renderViaHTTP(next.url, '/')

  at Object.destroy (production/eslint-plugin-deps/index.test.ts:149:23)

Read more about building and testing Next.js in contributing.md.

pnpm test-start test/e2e/no-eslint-warn-with-no-eslint-config/index.test.ts

  • no-eslint-warn-with-no-eslint-config > should warn with empty eslintrc
  • no-eslint-warn-with-no-eslint-config > should warn with empty eslint config in package.json
Expand output

● no-eslint-warn-with-no-eslint-config › should warn with empty eslintrc

expect(received).toContain(expected) // indexOf

Expected substring: "No ESLint configuration detected. Run next lint to begin setup"
Received string:    "   ▲ Next.js 15.5.1-canary.13
   - Experiments (use with caution):
     ✓ ppr (enabled by `__NEXT_EXPERIMENTAL_CACHE_COMPONENTS`)
     ✓ cacheComponents (enabled by `__NEXT_EXPERIMENTAL_CACHE_COMPONENTS`)
     ✓ clientSegmentCache (enabled by `__NEXT_EXPERIMENTAL_PPR`)
     ✓ clientParamParsing (enabled by `__NEXT_EXPERIMENTAL_PPR`)
     ✓ enablePrerenderSourceMaps (enabled by `experimental.cacheComponents`)·
   Checking validity of types ...
   Creating an optimized production build ...
 ✓ Compiled successfully in 659ms
   Collecting page data ...
   Generating static pages (0/3) ...
 ✓ Generating static pages (3/3)
   Finalizing page optimization ...
   Collecting build traces ...·
Route (pages)                                Size  First Load JS
┌ ○ /                                       258 B        95.6 kB
└ ○ /404                                    179 B        95.5 kB
+ First Load JS shared by all             95.3 kB
  ├ chunks/framework-f5224961f5a59dd0.js  57.4 kB
  ├ chunks/main-20dae7410cdc213e.js         37 kB
  └ other shared chunks (total)             882 B·
○  (Static)  prerendered as static content·
   ▲ Next.js 15.5.1-canary.13
   - Local:        http://localhost:37327
   - Network:      http://135.181.236.150:37327·
 ✓ Starting...
 ✓ Ready in 251ms
"

  43 |       await next.start()
  44 |
> 45 |       expect(next.cliOutput).toContain(
     |                              ^
  46 |         'No ESLint configuration detected. Run next lint to begin setup'
  47 |       )
  48 |     })

  at Object.toContain (e2e/no-eslint-warn-with-no-eslint-config/index.test.ts:45:30)

● no-eslint-warn-with-no-eslint-config › should warn with empty eslint config in package.json

expect(received).toContain(expected) // indexOf

Expected substring: "No ESLint configuration detected. Run next lint to begin setup"
Received string:    "   ▲ Next.js 15.5.1-canary.13
   - Experiments (use with caution):
     ✓ ppr (enabled by `__NEXT_EXPERIMENTAL_CACHE_COMPONENTS`)
     ✓ cacheComponents (enabled by `__NEXT_EXPERIMENTAL_CACHE_COMPONENTS`)
     ✓ clientSegmentCache (enabled by `__NEXT_EXPERIMENTAL_PPR`)
     ✓ clientParamParsing (enabled by `__NEXT_EXPERIMENTAL_PPR`)
     ✓ enablePrerenderSourceMaps (enabled by `experimental.cacheComponents`)·
   Checking validity of types ...
   Creating an optimized production build ...
 ✓ Compiled successfully in 884ms
   Collecting page data ...
   Generating static pages (0/3) ...
 ✓ Generating static pages (3/3)
   Finalizing page optimization ...
   Collecting build traces ...·
Route (pages)                                Size  First Load JS
┌ ○ /                                       258 B        95.6 kB
└ ○ /404                                    179 B        95.5 kB
+ First Load JS shared by all             95.3 kB
  ├ chunks/framework-f5224961f5a59dd0.js  57.4 kB
  ├ chunks/main-20dae7410cdc213e.js         37 kB
  └ other shared chunks (total)             882 B·
○  (Static)  prerendered as static content·
   ▲ Next.js 15.5.1-canary.13
   - Local:        http://localhost:35567
   - Network:      http://135.181.236.150:35567·
 ✓ Starting...
 ✓ Ready in 250ms
"

  59 |         await next.start()
  60 |
> 61 |         expect(next.cliOutput).toContain(
     |                                ^
  62 |           'No ESLint configuration detected. Run next lint to begin setup'
  63 |         )
  64 |       } finally {

  at Object.toContain (e2e/no-eslint-warn-with-no-eslint-config/index.test.ts:61:32)

Read more about building and testing Next.js in contributing.md.

pnpm test-start-turbo test/production/eslint/test/next-build-and-lint.test.ts (turbopack)

  • Next Build > production mode > first time setup - ESLint v8
  • Next Build > production mode > first time setup - ESLint v9
  • Next Build > production mode > first time setup with TypeScript - ESLint v8
  • Next Build > production mode > first time setup with TypeScript - ESLint v9
Expand output

● Next Build › production mode › first time setup - ESLint v8

expect(received).toContain(expected) // indexOf

Expected substring: "No ESLint configuration detected. Run next lint to begin setup"
Received string:    "   ▲ Next.js 15.5.1-canary.13 (Turbopack)·
   Checking validity of types ...
   Creating an optimized production build ...
 ✓ Finished writing to disk in 2ms
 ✓ Compiled successfully in 896ms
   Collecting page data ...
   Generating static pages (0/3) ...
 ✓ Generating static pages (3/3)
   Finalizing page optimization ...
   Collecting build traces ...·
Route (pages)                       Size  First Load JS
┌ ○ /                            9.26 kB         106 kB
└ ○ /404                         11.2 kB         108 kB
+ First Load JS shared by all      97 kB
  ├ chunks/168d89354d365f17.js   87.6 kB
  └ other shared chunks (total)  9.38 kB·
○  (Static)  prerendered as static content·
"

  30 |           const nextBuildCommand = await next.build()
  31 |           const buildOutput = nextBuildCommand.cliOutput
> 32 |           expect(buildOutput).toContain(
     |                               ^
  33 |             'No ESLint configuration detected. Run next lint to begin setup'
  34 |           )
  35 |

  at Object.toContain (production/eslint/test/next-build-and-lint.test.ts:32:31)

● Next Build › production mode › first time setup - ESLint v9

expect(received).toContain(expected) // indexOf

Expected substring: "No ESLint configuration detected. Run next lint to begin setup"
Received string:    "   ▲ Next.js 15.5.1-canary.13 (Turbopack)·
   Checking validity of types ...
   Creating an optimized production build ...
 ✓ Finished writing to disk in 3ms
 ✓ Compiled successfully in 1046ms
   Collecting page data ...
   Generating static pages (0/3) ...
 ✓ Generating static pages (3/3)
   Finalizing page optimization ...
   Collecting build traces ...·
Route (pages)                       Size  First Load JS
┌ ○ /                            9.26 kB         106 kB
└ ○ /404                         11.2 kB         108 kB
+ First Load JS shared by all      97 kB
  ├ chunks/168d89354d365f17.js   87.6 kB
  └ other shared chunks (total)  9.38 kB·
○  (Static)  prerendered as static content·
"

  113 |           const nextBuildCommand = await next.build()
  114 |           const buildOutput = nextBuildCommand.cliOutput
> 115 |           expect(buildOutput).toContain(
      |                               ^
  116 |             'No ESLint configuration detected. Run next lint to begin setup'
  117 |           )
  118 |

  at Object.toContain (production/eslint/test/next-build-and-lint.test.ts:115:31)

● Next Build › production mode › first time setup with TypeScript - ESLint v8

expect(received).toContain(expected) // indexOf

Expected substring: "No ESLint configuration detected. Run next lint to begin setup"
Received string:    "   ▲ Next.js 15.5.1-canary.13 (Turbopack)·
   Checking validity of types ...·
   We detected TypeScript in your project and created a tsconfig.json file for you.
   Creating an optimized production build ...
 ✓ Finished writing to disk in 3ms
 ✓ Compiled successfully in 996ms
   Collecting page data ...
   Generating static pages (0/3) ...
 ✓ Generating static pages (3/3)
   Finalizing page optimization ...
   Collecting build traces ...·
Route (pages)                       Size  First Load JS
┌ ○ /                            9.26 kB         106 kB
└ ○ /404                         11.2 kB         108 kB
+ First Load JS shared by all      97 kB
  ├ chunks/168d89354d365f17.js   87.6 kB
  └ other shared chunks (total)  9.38 kB·
○  (Static)  prerendered as static content·
"

  198 |           const nextBuildCommand = await next.build()
  199 |           const buildOutput = nextBuildCommand.cliOutput
> 200 |           expect(buildOutput).toContain(
      |                               ^
  201 |             'No ESLint configuration detected. Run next lint to begin setup'
  202 |           )
  203 |

  at Object.toContain (production/eslint/test/next-build-and-lint.test.ts:200:31)

● Next Build › production mode › first time setup with TypeScript - ESLint v9

expect(received).toContain(expected) // indexOf

Expected substring: "No ESLint configuration detected. Run next lint to begin setup"
Received string:    "   ▲ Next.js 15.5.1-canary.13 (Turbopack)·
   Checking validity of types ...·
   We detected TypeScript in your project and created a tsconfig.json file for you.
   Creating an optimized production build ...
 ✓ Finished writing to disk in 3ms
 ✓ Compiled successfully in 979ms
   Collecting page data ...
   Generating static pages (0/3) ...
 ✓ Generating static pages (3/3)
   Finalizing page optimization ...
   Collecting build traces ...·
Route (pages)                       Size  First Load JS
┌ ○ /                            9.26 kB         106 kB
└ ○ /404                         11.2 kB         108 kB
+ First Load JS shared by all      97 kB
  ├ chunks/168d89354d365f17.js   87.6 kB
  └ other shared chunks (total)  9.38 kB·
○  (Static)  prerendered as static content·
"

  281 |           const nextBuildCommand = await next.build()
  282 |           const buildOutput = nextBuildCommand.cliOutput
> 283 |           expect(buildOutput).toContain(
      |                               ^
  284 |             'No ESLint configuration detected. Run next lint to begin setup'
  285 |           )
  286 |

  at Object.toContain (production/eslint/test/next-build-and-lint.test.ts:283:31)

Read more about building and testing Next.js in contributing.md.

pnpm test-start-turbo test/production/app-dir/build-output/index.test.ts (turbopack)

  • production - app dir - build output > should always log version first then the rest jobs
Expand output

● production - app dir - build output › should always log version first then the rest jobs

expect(received).toBeLessThan(expected)

Expected: < -1
Received:   3

  27 |       'Linting and checking validity of types'
  28 |     )
> 29 |     expect(indexOfVersion).toBeLessThan(indexOfLinting)
     |                            ^
  30 |     expect(indexOfStartCompiling).toBeLessThan(indexOfLinting)
  31 |   })
  32 |

  at Object.toBeLessThan (production/app-dir/build-output/index.test.ts:29:28)

Read more about building and testing Next.js in contributing.md.

pnpm test test/integration/telemetry/test/config.test.js (turbopack)

  • config telemetry > production mode > emits telemetry for lint during build
  • config telemetry > production mode > emits telemetry for lint during build when '--no-lint' is specified
  • config telemetry > production mode > emits telemetry for lint during build when 'ignoreDuringBuilds' is specified
  • config telemetry > production mode > emits telemetry for next lint
Expand output

● config telemetry › production mode › emits telemetry for lint during build

TypeError: Cannot read properties of null (reading 'pop')

  176 |         try {
  177 |           const event1 = /NEXT_LINT_CHECK_COMPLETED[\s\S]+?{([\s\S}]+?)^}/m
> 178 |             .exec(stderr)
      |                   ^
  179 |             .pop()
  180 |
  181 |           expect(event1).toMatch(/"durationInSeconds": [\d]{1,}/)

  at Object.stderr (integration/telemetry/test/config.test.js:178:19)

● config telemetry › production mode › emits telemetry for lint during build when '--no-lint' is specified

expect(received).toContainEqual(expected) // deep equality

Expected value: {"featureName": "build-lint", "invocationCount": 0}
Received array: [{"featureName": "experimental/cacheComponents", "invocationCount": 0}, {"featureName": "experimental/optimizeCss", "invocationCount": 0}, {"featureName": "experimental/nextScriptWorkers", "invocationCount": 0}, {"featureName": "experimental/ppr", "invocationCount": 0}, {"featureName": "turbopackPersistentCaching", "invocationCount": 0}]

  213 |           'NEXT_BUILD_FEATURE_USAGE'
  214 |         )
> 215 |         expect(events).toContainEqual({
      |                        ^
  216 |           featureName: 'build-lint',
  217 |           invocationCount: 0,
  218 |         })

  at Object.toContainEqual (integration/telemetry/test/config.test.js:215:24)

● config telemetry › production mode › emits telemetry for lint during build when 'ignoreDuringBuilds' is specified

expect(received).toContainEqual(expected) // deep equality

Expected value: {"featureName": "build-lint", "invocationCount": 0}
Received array: [{"featureName": "experimental/cacheComponents", "invocationCount": 0}, {"featureName": "experimental/optimizeCss", "invocationCount": 0}, {"featureName": "experimental/nextScriptWorkers", "invocationCount": 0}, {"featureName": "experimental/ppr", "invocationCount": 0}, {"featureName": "turbopackPersistentCaching", "invocationCount": 0}]

  236 |           'NEXT_BUILD_FEATURE_USAGE'
  237 |         )
> 238 |         expect(events).toContainEqual({
      |                        ^
  239 |           featureName: 'build-lint',
  240 |           invocationCount: 0,
  241 |         })

  at Object.toContainEqual (integration/telemetry/test/config.test.js:238:24)

● config telemetry › production mode › emits telemetry for next lint

TypeError: Cannot read properties of null (reading 'pop')

  254 |
  255 |         const event1 = /NEXT_LINT_CHECK_COMPLETED[\s\S]+?{([\s\S]+?)^}/m
> 256 |           .exec(stderr)
      |                 ^
  257 |           .pop()
  258 |
  259 |         expect(event1).toMatch(/"durationInSeconds": [\d]{1,}/)

  at Object.stderr (integration/telemetry/test/config.test.js:256:17)

Read more about building and testing Next.js in contributing.md.

pnpm test-start test/e2e/app-dir/app/standalone-gsp.test.ts

  • output: standalone with getStaticProps > should work correctly with output standalone
Expand output

● output: standalone with getStaticProps › should work correctly with output standalone

thrown: "Exceeded timeout of 120000 ms for a test.
Add a timeout value to this test to increase the timeout, if this is a long-running test. See https://jestjs.io/docs/api#testname-fn-timeout."

  57 |     })
  58 |
> 59 |     it('should work correctly with output standalone', async () => {
     |     ^
  60 |       const tmpFolder = path.join(os.tmpdir(), 'next-standalone-' + Date.now())
  61 |       await fs.move(path.join(next.testDir, '.next/standalone'), tmpFolder)
  62 |       let server: any

  at it (e2e/app-dir/app/standalone-gsp.test.ts:59:5)
  at Object.describe (e2e/app-dir/app/standalone-gsp.test.ts:15:3)

Read more about building and testing Next.js in contributing.md.

Copy link
Contributor

@vercel vercel bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Additional Comments:

test/lib/next-test-utils.ts (lines 486-492):

The nextLint function tries to execute the removed next lint command, which will cause all tests using this function to fail.

View Details
📝 Patch Details
diff --git a/test/development/next-lint-eslint-formatter-compact/index.test.ts b/test/development/next-lint-eslint-formatter-compact/index.test.ts
index 095b249fc0..190faaba3d 100644
--- a/test/development/next-lint-eslint-formatter-compact/index.test.ts
+++ b/test/development/next-lint-eslint-formatter-compact/index.test.ts
@@ -1,6 +1,6 @@
 import { nextTestSetup } from 'e2e-utils'
 import { readFileSync } from 'fs'
-import { nextLint } from 'next-test-utils'
+import { execSync } from 'child_process'
 
 describe('next-lint-eslint-formatter-compact', () => {
   const { next } = nextTestSetup({
@@ -10,14 +10,20 @@ describe('next-lint-eslint-formatter-compact', () => {
 
   it('should format flag "compact" creates a file respecting the chosen format', async () => {
     const filePath = `${next.testDir}/output/output.txt`
-    const { stdout, stderr } = await nextLint(
-      next.testDir,
-      ['--format', 'compact', '--output-file', filePath],
-      {
-        stdout: true,
-        stderr: true,
-      }
-    )
+    let stdout = ''
+    let stderr = ''
+    try {
+      stdout = execSync(
+        `npx eslint . --format compact --output-file ${filePath}`,
+        {
+          cwd: next.testDir,
+          encoding: 'utf8',
+          stdio: ['pipe', 'pipe', 'pipe']
+        }
+      )
+    } catch (error: any) {
+      stderr = error.stderr || error.message
+    }
 
     const cliOutput = stdout + stderr
     const fileOutput = readFileSync(filePath, 'utf8')
@@ -40,14 +46,20 @@ describe('next-lint-eslint-formatter-compact', () => {
 
   it('should show error message when the file path is a directory', async () => {
     const filePath = next.testDir
-    const { stdout, stderr } = await nextLint(
-      next.testDir,
-      ['--format', 'compact', '--output-file', filePath],
-      {
-        stdout: true,
-        stderr: true,
-      }
-    )
+    let stdout = ''
+    let stderr = ''
+    try {
+      stdout = execSync(
+        `npx eslint . --format compact --output-file ${filePath}`,
+        {
+          cwd: next.testDir,
+          encoding: 'utf8',
+          stdio: ['pipe', 'pipe', 'pipe']
+        }
+      )
+    } catch (error: any) {
+      stderr = error.stderr || error.message
+    }
 
     const cliOutput = stdout + stderr
     console.log({ cliOutput })
diff --git a/test/integration/eslint/test/lint-cache.test.js b/test/integration/eslint/test/lint-cache.test.js
index 2004b59de4..a53fb45e9d 100644
--- a/test/integration/eslint/test/lint-cache.test.js
+++ b/test/integration/eslint/test/lint-cache.test.js
@@ -1,13 +1,17 @@
+// NOTE: These tests are disabled because the `next lint` command has been deprecated
+// and removed from Next.js CLI in favor of using ESLint directly.
+// See: https://nextjs.org/blog/next-15-5#next-lint-deprecation
+
 import fs from 'fs-extra'
 
 import { join } from 'path'
 
-import { nextLint } from 'next-test-utils'
+// import { nextLint } from 'next-test-utils' // Function removed - next lint deprecated
 
 const dirEslintCache = join(__dirname, '../eslint-cache')
 const dirEslintCacheCustomDir = join(__dirname, '../eslint-cache-custom-dir')
 
-test('eslint caching is enabled by default', async () => {
+test.skip('eslint caching is enabled by default', async () => {
   const cacheDir = join(dirEslintCache, '.next', 'cache')
 
   await fs.remove(cacheDir)
@@ -19,7 +23,7 @@ test('eslint caching is enabled by default', async () => {
   expect(cacheExists).toBe(true)
 })
 
-test('eslint caching is disabled with the --no-cache flag', async () => {
+test.skip('eslint caching is disabled with the --no-cache flag', async () => {
   const cacheDir = join(dirEslintCache, '.next', 'cache')
 
   await fs.remove(cacheDir)
@@ -28,7 +32,7 @@ test('eslint caching is disabled with the --no-cache flag', async () => {
   expect(fs.existsSync(join(cacheDir, 'eslint/'))).toBe(false)
 })
 
-test('the default eslint cache lives in the user defined build directory', async () => {
+test.skip('the default eslint cache lives in the user defined build directory', async () => {
   const oldCacheDir = join(dirEslintCacheCustomDir, '.next', 'cache')
   const newCacheDir = join(dirEslintCacheCustomDir, 'build', 'cache')
 
@@ -45,7 +49,7 @@ test('the default eslint cache lives in the user defined build directory', async
   expect(cacheExists).toBe(true)
 })
 
-test('the --cache-location flag allows the user to define a separate cache location', async () => {
+test.skip('the --cache-location flag allows the user to define a separate cache location', async () => {
   const cacheFile = join(dirEslintCache, '.eslintcache')
 
   await fs.remove(cacheFile)
@@ -65,7 +69,7 @@ const getEslintCacheContent = async (cacheDir) => {
   return await fs.readFile(cacheFile, 'utf8')
 }
 
-test('the default eslint caching strategy is metadata', async () => {
+test.skip('the default eslint caching strategy is metadata', async () => {
   const cacheDir = join(dirEslintCache, '.next', 'cache')
 
   await fs.remove(cacheDir)
@@ -81,7 +85,7 @@ test('the default eslint caching strategy is metadata', async () => {
   expect(metadataStrategyCache).toBe(defaultStrategyCache)
 })
 
-test('cache with content strategy is different from the one with default strategy', async () => {
+test.skip('cache with content strategy is different from the one with default strategy', async () => {
   const cacheDir = join(dirEslintCache, '.next', 'cache')
 
   await fs.remove(cacheDir)
diff --git a/test/integration/eslint/test/next-lint.test.js b/test/integration/eslint/test/next-lint.test.js
index b88bd98ef3..db24d112fa 100644
--- a/test/integration/eslint/test/next-lint.test.js
+++ b/test/integration/eslint/test/next-lint.test.js
@@ -1,10 +1,14 @@
+// NOTE: These tests are disabled because the `next lint` command has been deprecated
+// and removed from Next.js CLI in favor of using ESLint directly.
+// See: https://nextjs.org/blog/next-15-5#next-lint-deprecation
+
 import fs from 'fs-extra'
 import os from 'os'
 
 import { join } from 'path'
 
 import findUp from 'next/dist/compiled/find-up'
-import { nextLint } from 'next-test-utils'
+// import { nextLint } from 'next-test-utils' // Function removed - next lint deprecated
 
 const dirFirstTimeSetup = join(__dirname, '../first-time-setup')
 const dirCustomConfig = join(__dirname, '../custom-config')
@@ -29,7 +33,7 @@ const mjsCjsLinting = join(__dirname, '../mjs-cjs-linting')
 const dirTypescript = join(__dirname, '../with-typescript')
 const formatterAsync = join(__dirname, '../formatter-async/format.js')
 
-describe('Next Lint', () => {
+describe.skip('Next Lint (DEPRECATED - command removed)', () => {
   describe('First Time Setup ', () => {
     async function nextLintTemp(setupCallback, isApp = false) {
       const folder = join(os.tmpdir(), Math.random().toString(36).substring(2))
diff --git a/test/integration/telemetry/test/config.test.js b/test/integration/telemetry/test/config.test.js
index 95e75e96a5..907476da5f 100644
--- a/test/integration/telemetry/test/config.test.js
+++ b/test/integration/telemetry/test/config.test.js
@@ -5,7 +5,7 @@ import {
   killApp,
   launchApp,
   nextBuild,
-  nextLint,
+  // nextLint, // Function removed - next lint deprecated
   waitFor,
 } from 'next-test-utils'
 import fs from 'fs-extra'
@@ -241,15 +241,16 @@ describe('config telemetry', () => {
         })
       })
 
-      it('emits telemetry for `next lint`', async () => {
+      it.skip('emits telemetry for `next lint` (DEPRECATED)', async () => {
         await fs.writeFile(
           path.join(appDir, '.eslintrc'),
           `{ "root": true, "extends": "next" }`
         )
-        const { stderr } = await nextLint(appDir, [], {
-          stderr: true,
-          env: { NEXT_TELEMETRY_DEBUG: 1 },
-        })
+        // const { stderr } = await nextLint(appDir, [], { // Function removed - deprecated
+        //   stderr: true,
+        //   env: { NEXT_TELEMETRY_DEBUG: 1 },
+        // })
+        const stderr = '' // Disabled test - nextLint deprecated
         await fs.remove(path.join(appDir, '.eslintrc'))
 
         const event1 = /NEXT_LINT_CHECK_COMPLETED[\s\S]+?{([\s\S]+?)^}/m
diff --git a/test/lib/next-test-utils.ts b/test/lib/next-test-utils.ts
index 9a4753a8d2..4dfa23d6ca 100644
--- a/test/lib/next-test-utils.ts
+++ b/test/lib/next-test-utils.ts
@@ -483,14 +483,6 @@ export function nextBuild(
   return runNextCommand(['build', dir, ...args], opts)
 }
 
-export function nextLint(
-  dir: string,
-  args: string[] = [],
-  opts: NextOptions = {}
-) {
-  return runNextCommand(['lint', dir, ...args], opts)
-}
-
 export function nextTest(
   dir: string,
   args: string[] = [],
diff --git a/test/production/eslint/test/next-build-and-lint.test.ts b/test/production/eslint/test/next-build-and-lint.test.ts
index 279ad0bd33..75c784bebb 100644
--- a/test/production/eslint/test/next-build-and-lint.test.ts
+++ b/test/production/eslint/test/next-build-and-lint.test.ts
@@ -29,18 +29,19 @@ describe('Next Build', () => {
 
           const nextBuildCommand = await next.build()
           const buildOutput = nextBuildCommand.cliOutput
-          expect(buildOutput).toContain(
-            'No ESLint configuration detected. Run next lint to begin setup'
-          )
+          // expect(buildOutput).toContain(
+          //   'No ESLint configuration detected. Run next lint to begin setup'
+          // )
+          // Note: The build output may no longer mention `next lint` since the command is deprecated
 
-          // TODO: Should we exit non-zero here if the config was created? Should we maybe even directly start linting?
+          // Verify that `next lint` command is no longer available (as it's been deprecated)
           expect(() => {
             execSync(`pnpm next lint --strict`, {
               cwd: next.testDir,
               encoding: 'utf8',
               stdio: 'inherit',
             })
-          }).toThrow('Command failed: pnpm next lint --strict')
+          }).toThrow() // Should fail because command doesn't exist
 
           const eslintConfigAfterSetupJSON = execSync(
             `pnpm eslint --print-config pages/index.js`,
@@ -112,18 +113,19 @@ describe('Next Build', () => {
 
           const nextBuildCommand = await next.build()
           const buildOutput = nextBuildCommand.cliOutput
-          expect(buildOutput).toContain(
-            'No ESLint configuration detected. Run next lint to begin setup'
-          )
+          // expect(buildOutput).toContain(
+          //   'No ESLint configuration detected. Run next lint to begin setup'
+          // )
+          // Note: The build output may no longer mention `next lint` since the command is deprecated
 
-          // TODO: Should we exit non-zero here if the config was created? Should we maybe even directly start linting?
+          // Verify that `next lint` command is no longer available (as it's been deprecated)
           expect(() => {
             execSync(`pnpm next lint --strict`, {
               cwd: next.testDir,
               encoding: 'utf8',
               stdio: 'inherit',
             })
-          }).toThrow('Command failed: pnpm next lint --strict')
+          }).toThrow() // Should fail because command doesn't exist
 
           const eslintConfigAfterSetupJSON = execSync(
             // TODO(jiwon): remove `ESLINT_USE_FLAT_CONFIG=false` when we create the config for ESLint 9.
@@ -197,18 +199,19 @@ describe('Next Build', () => {
 
           const nextBuildCommand = await next.build()
           const buildOutput = nextBuildCommand.cliOutput
-          expect(buildOutput).toContain(
-            'No ESLint configuration detected. Run next lint to begin setup'
-          )
+          // expect(buildOutput).toContain(
+          //   'No ESLint configuration detected. Run next lint to begin setup'
+          // )
+          // Note: The build output may no longer mention `next lint` since the command is deprecated
 
-          // TODO: Should we exit non-zero here if the config was created? Should we maybe even directly start linting?
+          // Verify that `next lint` command is no longer available (as it's been deprecated)
           expect(() => {
             execSync(`pnpm next lint --strict`, {
               cwd: next.testDir,
               encoding: 'utf8',
               stdio: 'inherit',
             })
-          }).toThrow('Command failed: pnpm next lint --strict')
+          }).toThrow() // Should fail because command doesn't exist
 
           const eslintConfigAfterSetupJSON = execSync(
             `pnpm eslint --print-config pages/index.tsx`,
@@ -280,18 +283,19 @@ describe('Next Build', () => {
 
           const nextBuildCommand = await next.build()
           const buildOutput = nextBuildCommand.cliOutput
-          expect(buildOutput).toContain(
-            'No ESLint configuration detected. Run next lint to begin setup'
-          )
+          // expect(buildOutput).toContain(
+          //   'No ESLint configuration detected. Run next lint to begin setup'
+          // )
+          // Note: The build output may no longer mention `next lint` since the command is deprecated
 
-          // TODO: Should we exit non-zero here if the config was created? Should we maybe even directly start linting?
+          // Verify that `next lint` command is no longer available (as it's been deprecated)
           expect(() => {
             execSync(`pnpm next lint --strict`, {
               cwd: next.testDir,
               encoding: 'utf8',
               stdio: 'inherit',
             })
-          }).toThrow('Command failed: pnpm next lint --strict')
+          }).toThrow() // Should fail because command doesn't exist
 
           const eslintConfigAfterSetupJSON = execSync(
             // TODO(jiwon): remove `ESLINT_USE_FLAT_CONFIG=false` when we create the config for ESLint 9.

Analysis

The nextLint function in the test utilities calls runNextCommand(['lint', dir, ...args], opts) on line 491, but the lint command has been completely removed from the Next.js CLI in this changeset. This will cause runtime failures in multiple test files that depend on this function:

  • test/development/next-lint-eslint-formatter-compact/index.test.ts (2 test cases)
  • test/integration/eslint/test/lint-cache.test.js (9 test cases)
  • test/integration/eslint/test/next-lint.test.js (many test cases)

The function should either be removed entirely along with all the tests that use it, or the tests should be updated to use the ESLint CLI directly instead of the removed next lint command. Since the intent appears to be removing Next.js's built-in lint functionality in favor of native ESLint CLI usage, the most appropriate fix would be to remove this function and update the affected tests accordingly.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
created-by: Next.js team PRs by the Next.js team. Documentation Related to Next.js' official documentation. type: next
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants