7 min read

Biome vs ESLint + Prettier for Next.js 16: Which One to Pick in 2026

Mehdi Rezaei
Mehdi
Author
Engineering
Software
Technology

Next.js 16 removed next lint, and next build no longer runs a linter for you. That small change forces a decision on every new and upgraded project: run ESLint and Prettier yourself, or switch to Biome, which does both jobs in one binary. create-next-app now asks the question directly with a choice of ESLint, Biome, or None.

My short answer: start new Next.js apps on Biome, and keep ESLint plus Prettier when a plugin you depend on has no Biome match or when your team leans on typed lint rules from typescript-eslint. The rest of this post is the reasoning, the setup for each, and the cases where I would not switch.

What changed in Next.js 16

The Next.js 16 upgrade guide lists three changes that matter here. Next.js removed the next lint command and the eslint option in next.config. And next build stopped linting, so CI only catches lint errors if you run the linter as its own step.

For existing projects there is a codemod, npx @next/codemod@canary next-lint-to-eslint-cli ., that rewrites your scripts to call the ESLint CLI. The guide also notes that eslint-config-next@16 needs ESLint 9 or later, and that ESLint 10 support starts at eslint-config-next@16.4.0. If you already moved to Turbopack (I covered that in Turbopack vs Webpack in Next.js 16), this is the other tooling change to plan for in the same upgrade.

Where each tool stands in late 2026

ESLint 10.0.0 shipped on 6 February 2026, according to the ESLint release post. It dropped the old eslintrc system: ESLint now ignores .eslintrc.* and .eslintignore, and flat config in eslint.config.js is the only format. It also looks up the config file from the directory of each linted file, which helps monorepos. Node versions before 20.19.0 are no longer supported.

Prettier is still on the 3.x line. The Prettier blog archive lists 3.8 in January 2026 and 3.9 in June 2026 with parser upgrades and framework syntax support.

Biome moved faster. Version 2.0 in June 2025 added type-aware lint rules that do not need the TypeScript compiler, plus GritQL plugins. The Biome 2.0 post said its noFloatingPromises rule caught about 75% of the cases typescript-eslint catches in preliminary testing. The 2.6 line, released in October 2026 per the Biome releases page, added YAML formatting, a biome migrate stylelint command, and moved 59 nursery rules into stable groups, including Drizzle rules that flag delete and update calls without a where clause.

Biome vs ESLint + Prettier, side by side

  • Tools to install: Biome is one package. The ESLint route needs eslint, eslint-config-next, usually typescript-eslint, Prettier, and eslint-config-prettier to stop the two from fighting over style rules.
  • Config files: Biome uses one biome.json. The other route has eslint.config.mjs plus a Prettier config and ignore file.
  • Formatting: Biome follows Prettier's philosophy of few options. Its docs keep a list of intentional differences from Prettier, so expect a one-time diff when you switch.
  • Next.js rules: Biome has a next domain that turns on when next 14 or later is in your dependencies. It includes rules such as noImgElement, useInlineScriptId, and noSyncScripts. ESLint gets the full rule set from @next/eslint-plugin-next.
  • Type-aware linting: typescript-eslint asks the TypeScript type checker about every file. Its own docs say these rules are slower than normal lint rules but much more powerful. Biome uses its own inference engine, which is cheaper but still catches fewer cases.
  • Plugins: ESLint has the largest plugin ecosystem in JavaScript. Biome supports GritQL plugins for JavaScript, TypeScript, CSS, and JSON, and JavaScript plugins in developer preview.
  • Other file types: Biome lints and formats JSON, CSS, SCSS, GraphQL, YAML, and Markdown. Vue, Svelte, and Astro support is still marked experimental in its language support table.

Setting up Biome on a Next.js 16 project

For a new project, npx create-next-app@latest my-app --biome generates the config and two scripts: "lint": "biome check" and "format": "biome format --write". That is the whole setup.

For an existing app that already has ESLint and Prettier, use the migration commands:

  1. Install Biome as a dev dependency and run npx biome init. Inside a Git repo, recent versions turn on VCS integration so Biome respects .gitignore.
  2. Run npx biome migrate eslint --write. It reads flat and legacy configs, follows extends, and ports rules, globals, overrides, and ignore patterns. By default it only migrates rules that are identical to their ESLint source; add --include-inspired to bring over close matches.
  3. Run npx biome migrate prettier --write. It writes every Prettier option explicitly so your output stays the same.
  4. Turn on the domains you need, such as "next": "recommended" and "react": "recommended", under linter.domains.
  5. Run npx biome check --write once and commit the formatting diff as its own commit, so git blame stays readable.
  6. Remove ESLint, Prettier, and their plugins, and swap the editor extensions for Biome's.

Add biome ci as a separate step in your pipeline. Since next build no longer lints, skipping this step means nothing checks your code before deploy. It fits next to the test job I described in Playwright vs Cypress for Next.js CI.

Setting up ESLint 10 + Prettier the clean way

If you stay on ESLint, run the Next.js codemod first, then check that eslint.config.mjs exports a flat config built with defineConfig. Add typescript-eslint with recommendedTypeChecked and parserOptions.projectService: true if you want typed rules such as no-floating-promises and no-misused-promises. Put eslint-config-prettier last so ESLint does not report style issues that Prettier will rewrite anyway.

Then run them as two scripts, eslint . and prettier --check ., in CI. Keep formatting out of ESLint. The setup stays easier to debug when one tool reports problems and the other only rewrites whitespace.

When I would keep ESLint

  • You rely on a plugin with no Biome match, for example a company rule set, a rule option the Biome port does not implement yet, or a framework plugin for Vue or Svelte templates that you need to be stable today.
  • Your team depends on the full typed rule set from typescript-eslint and accepts the slower lint run. Biome's type-aware rules are improving each release, but the gap is real.
  • You have custom ESLint rules written in JavaScript. Rewriting them as GritQL is possible for pattern checks but not always for rules that need deep semantic data.

When Biome is the better call

  • A new Next.js, React, or plain TypeScript project where the default rules cover what you care about.
  • Monorepos where one binary and one config shared across packages is easier than many ESLint configs. Biome configs can now extend other configs up to ten levels deep.
  • Projects with lots of JSON, CSS, and YAML next to the TypeScript, since one tool formats every file.
  • Teams tired of version conflicts between ESLint plugins after each major release.

My default stack for client projects

New Next.js 16 apps get Biome with the next and react domains on, plus biome ci in the pipeline. I pair it with Drizzle, which now has its own Biome domain (see Drizzle vs Prisma for why I lean that way). Inherited projects with years of ESLint config stay on ESLint 10 and Prettier until there is a clear reason to move, because a linter swap in the middle of feature work buys little.

If you switch, do it in one focused pull request: migrate, format, remove the old packages, update CI. Mixing a tooling change with product changes is what makes these migrations painful.

Share this article

Biome vs ESLint + Prettier for Next.js 16: Which One to Pick in 2026 | Mehd.ir