Next.js 15 projects demand fast, reliable tooling that scales with growing codebases. The traditional Prettier+ESLint combination has dominated for years, but Biome presents a unified alternative that promises significant performance improvements and simplified configuration.
Understanding the Tooling Landscape
The traditional approach combines two distinct tools: Prettier handles code formatting while ESLint manages linting and code quality rules. This separation works but introduces complexity—two configuration files, potential conflicts between formatters and linters, and slower execution times as files pass through multiple tools sequentially.
Biome takes a different approach by unifying formatting and linting into a single tool written in Rust. This architectural decision enables parallel processing and eliminates the coordination overhead between separate tools. For Next.js 15 projects leveraging server components and the app router, this performance difference becomes particularly noticeable in larger codebases.
Performance Benchmarks and Real-World Impact
Biome's Rust foundation delivers measurable performance advantages. In typical Next.js projects with 500+ files, Biome completes formatting and linting operations 10-35x faster than the Prettier+ESLint combination. This speed difference compounds during development when tools run on every file save.
Consider a mid-sized Next.js application with the following structure:
1app/
2├── (auth)/
3│ ├── login/
4│ └── register/
5├── (dashboard)/
6│ ├── analytics/
7│ └── settings/
8├── api/
9│ └── [...multiple route handlers]
10└── components/
11 └── [...shared components]With Prettier+ESLint, pre-commit hooks might take 8-12 seconds to process changed files. Biome typically completes the same operation in under 1 second. This difference affects developer experience significantly—faster feedback loops mean less context switching and interruption.
Configuration and Setup
Setting up Biome in a Next.js 15 project requires minimal configuration. The tool uses a single biome.json file:
1{
2 "$schema": "https://biomejs.dev/schemas/1.5.0/schema.json",
3 "organizeImports": {
4 "enabled": true
5 },
6 "linter": {
7 "enabled": true,
8 "rules": {
9 "recommended": true,
10 "suspicious": {
11 "noExplicitAny": "error",
12 "noArrayIndexKey": "warn"
13 },
14 "style": {
15 "useImportType": "error",
16 "noNonNullAssertion": "warn"
17 }
18 }
19 },
20 "formatter": {
21 "enabled": true,
22 "indentStyle": "space",
23 "indentWidth": 2,
24 "lineWidth": 100
25 },
26 "javascript": {
27 "formatter": {
28 "quoteStyle": "single",
29 "trailingComma": "es5"
30 }
31 }
32}The equivalent Prettier+ESLint setup requires multiple files. A typical configuration includes .prettierrc.js, .eslintrc.js, and often .eslintignore and .prettierignore:
1// .eslintrc.js
2module.exports = {
3 extends: [
4 'next/core-web-vitals',
5 'plugin:@typescript-eslint/recommended',
6 'prettier'
7 ],
8 plugins: ['@typescript-eslint'],
9 rules: {
10 '@typescript-eslint/no-explicit-any': 'error',
11 '@typescript-eslint/no-unused-vars': ['error', {
12 argsIgnorePattern: '^_'
13 }],
14 'react/jsx-key': 'warn'
15 }
16}
17
18// .prettierrc.js
19module.exports = {
20 semi: true,
21 trailingComma: 'es5',
22 singleQuote: true,
23 printWidth: 100,
24 tabWidth: 2
25}The multi-file approach increases maintenance burden, especially when rules conflict or require synchronization across tools.
Handling Next.js 15 Specific Patterns
Next.js 15 introduces patterns that require specific linting considerations. Server components, server actions, and the app router create new scenarios where traditional ESLint rules may not apply correctly.
Biome handles modern React patterns natively. For server components, the tool correctly identifies client/server boundaries:
1// app/dashboard/page.tsx
2import { Suspense } from 'react'
3import { AnalyticsChart } from '@/components/analytics-chart'
4import { getAnalyticsData } from '@/lib/data'
5
6export default async function DashboardPage() {
7 const data = await getAnalyticsData()
8
9 return (
10 <div className="dashboard">
11 <Suspense fallback={<ChartSkeleton />}>
12 <AnalyticsChart data={data} />
13 </Suspense>
14 </div>
15 )
16}Biome recognizes this as a server component and applies appropriate rules without requiring special configuration. The tool understands that async components are valid in the app router and won't flag them as errors.
ESLint requires additional plugins and configuration to handle these patterns correctly. The eslint-plugin-react-server-components plugin helps, but it adds another dependency and configuration layer:
1// Additional ESLint configuration needed
2module.exports = {
3 extends: [
4 'next/core-web-vitals',
5 'plugin:react-server-components/recommended'
6 ],
7 plugins: ['react-server-components'],
8 rules: {
9 'react-server-components/use-client': 'error'
10 }
11}Import Sorting and Organization
Advertisement
Import organization becomes crucial in larger Next.js projects where files might import from multiple sources—React, Next.js internals, third-party libraries, and local modules. Biome includes built-in import sorting that groups and orders imports automatically:
1// Before formatting
2import { Button } from '@/components/ui/button'
3import { useState } from 'react'
4import type { User } from '@/types'
5import Link from 'next/link'
6import { cn } from '@/lib/utils'
7
8// After Biome formatting
9import { useState } from 'react'
10import Link from 'next/link'
11import type { User } from '@/types'
12
13import { cn } from '@/lib/utils'
14import { Button } from '@/components/ui/button'The Prettier+ESLint approach requires additional plugins like eslint-plugin-import or prettier-plugin-sort-imports, each with their own configuration syntax and potential compatibility issues.
Migration Strategies and Trade-offs
Migrating from Prettier+ESLint to Biome in an existing Next.js project requires careful planning. Biome doesn't achieve 100% parity with ESLint's extensive rule ecosystem. Projects heavily dependent on specific ESLint plugins—particularly those for accessibility (eslint-plugin-jsx-a11y) or testing libraries—may need to maintain ESLint alongside Biome temporarily.
A hybrid approach works for teams not ready to fully commit:
1// package.json scripts
2{
3 "scripts": {
4 "format": "biome format --write .",
5 "lint": "biome lint .",
6 "lint:eslint": "eslint . --ext .ts,.tsx",
7 "check": "biome check --apply ."
8 }
9}This configuration uses Biome for formatting and basic linting while keeping ESLint for specialized rules. The performance benefits remain substantial since Biome handles the majority of operations.
Teams should evaluate their specific ESLint plugin dependencies. Common plugins like @typescript-eslint, eslint-plugin-react, and eslint-plugin-react-hooks have equivalent rules in Biome. However, specialized plugins for specific frameworks or testing libraries may not have direct replacements.
Editor Integration and Developer Experience
Both tooling approaches integrate with VS Code, but the experience differs. Biome's VS Code extension provides real-time feedback with minimal configuration. The extension handles formatting on save and displays linting errors inline without requiring separate Prettier and ESLint extensions.
The traditional setup requires coordinating multiple extensions—ESLint, Prettier, and sometimes additional formatters. Developers must configure settings to prevent conflicts, such as disabling ESLint's formatting rules when Prettier runs:
1// .vscode/settings.json for Prettier+ESLint
2{
3 "editor.defaultFormatter": "esbenp.prettier-vscode",
4 "editor.formatOnSave": true,
5 "editor.codeActionsOnSave": {
6 "source.fixAll.eslint": true
7 },
8 "eslint.validate": ["javascript", "typescript", "typescriptreact"]
9}Biome simplifies this to:
1// .vscode/settings.json for Biome
2{
3 "editor.defaultFormatter": "biomejs.biome",
4 "editor.formatOnSave": true,
5 "editor.codeActionsOnSave": {
6 "quickfix.biome": true
7 }
8}Production Considerations
CI/CD pipelines benefit significantly from Biome's performance characteristics. A typical GitHub Actions workflow that previously took 2-3 minutes for linting and formatting can complete in under 30 seconds:
1# .github/workflows/ci.yml
2name: CI
3on: [push, pull_request]
4
5jobs:
6 check:
7 runs-on: ubuntu-latest
8 steps:
9 - uses: actions/checkout@v4
10 - uses: actions/setup-node@v4
11 with:
12 node-version: '20'
13 - run: npm ci
14 - run: npx @biomejs/biome check .This speed improvement reduces queue times in busy repositories and provides faster feedback on pull requests. For teams practicing continuous integration with frequent commits, these seconds accumulate into significant time savings.
The simplified configuration also reduces maintenance overhead. Teams spend less time debugging conflicts between Prettier and ESLint or updating multiple configuration files when coding standards evolve.
Making the Decision
Biome suits Next.js 15 projects prioritizing performance and simplified tooling. Teams starting new projects or those willing to adapt their linting rules will benefit most from the unified approach. The performance gains become more pronounced as codebases grow beyond 10,000 lines.
Prettier+ESLint remains viable for projects with established configurations or heavy dependencies on specific ESLint plugins. The mature ecosystem provides solutions for virtually every linting scenario, and the separation of concerns between formatting and linting offers flexibility some teams prefer.
The choice ultimately depends on project requirements, team preferences, and existing tooling investments. Biome's trajectory suggests it will continue closing feature gaps while maintaining its performance advantages. For new Next.js 15 projects without legacy constraints, Biome presents a compelling modern alternative worth serious consideration.





