ESLint vs Biome(@biomejs/biome) — JavaScript/TypeScript リンター比較
注記: npm上には
biomeという名前で環境変数管理ツールが存在しますが、本記事では現在JavaScriptエコシステムで広く比較対象となっている @biomejs/biome(旧Rome — 高速なリンター・フォーマッター)と ESLint を比較します。biome(環境変数管理)はESLintと用途がまったく異なるため、比較記事としての実用的価値を優先し、このように構成しました。
1. 結論
既存の大規模プロジェクトや、細かいルールカスタマイズ・豊富なプラグインが必要な場合は ESLint を選んでください。新規プロジェクトで高速なリント+フォーマットを一括導入し、設定の手間を最小限にしたい場合は Biome が最適です。両者は共存も可能なので、段階的な移行という選択肢もあります。
2. 比較表
| 観点 | ESLint | Biome (@biomejs/biome) |
|---|---|---|
| 初回リリース | 2013年 | 2023年(Rome から fork) |
| 実装言語 | JavaScript (Node.js) | Rust |
| 主な機能 | リンター | リンター + フォーマッター + インポート整理 |
| 対応言語 | JS / TS / JSX / TSX(プラグインで Vue, Svelte 等) | JS / TS / JSX / TSX / JSON / CSS / GraphQL |
| ルール数(組み込み) | 約 300+ | 約 300+(v1.x 時点) |
| プラグインエコシステム | ★★★★★(数千のプラグイン) | ★★☆☆☆(プラグインシステムは開発中) |
| 設定ファイル | eslint.config.js(Flat Config) | biome.json / biome.jsonc |
| TypeScript 対応 | typescript-eslint が必要 | ゼロ設定で対応 |
| フォーマッター | 別途 Prettier 等が必要 | 内蔵(Prettier 互換 97%+) |
| 実行速度 | 普通〜遅い | 非常に高速(10〜100倍) |
| npm install サイズ | ~30MB+(プラグイン込み) | ~10MB 程度 |
| 学習コスト | 中〜高(設定が複雑になりがち) | 低(少ない設定で始められる) |
| IDE 対応 | VS Code, JetBrains 等 充実 | VS Code 拡張あり、JetBrains 対応中 |
| CI 統合 | 非常に成熟 | GitHub Actions 等対応済み |
| ライセンス | MIT | MIT |
3. それぞれの強み
ESLint の強み
- 圧倒的なプラグインエコシステム:
eslint-plugin-react,eslint-plugin-import,eslint-plugin-vue,eslint-plugin-testing-libraryなど、あらゆるフレームワーク・ライブラリに対応するプラグインが存在します。 - カスタムルールの作成が容易: AST ベースの Visitor パターンで独自ルールを JavaScript で記述できます。社内固有のコーディング規約を強制したい場合に強力です。
- Flat Config による設定の近代化: v9 以降の Flat Config により、設定の共有・合成が格段にシンプルになりました。
- 長年の実績と情報量: Stack Overflow、ブログ記事、書籍など、トラブルシューティング情報が豊富です。
Biome の強み
- 圧倒的な速度: Rust 実装により、数千ファイルのプロジェクトでも数百ミリ秒でリント+フォーマットが完了します。
- オールインワン: リンター・フォーマッター・インポートソートが 1 つのツールに統合されており、
eslint+prettier+eslint-plugin-importの組み合わせを置き換えられます。 - ゼロコンフィグで TypeScript 対応: 追加パッケージなしで TypeScript / JSX / TSX をそのまま解析できます。
- Prettier 互換のフォーマッター: ESLint と Prettier の競合問題(
eslint-config-prettierの設定など)に悩む必要がありません。 - わかりやすいエラーメッセージ: Rust コンパイラに影響を受けた、詳細で読みやすい診断メッセージを出力します。
4. コード例で比較
セットアップ
# ESLint のセットアップ
npm install -D eslint @eslint/js typescript-eslint
# Biome のセットアップ
npm install -D @biomejs/biome
npx biome init
設定ファイル
ESLint(eslint.config.js)
// eslint.config.js
import eslint from "@eslint/js";
import tseslint from "typescript-eslint";
export default tseslint.config(
eslint.configs.recommended,
...tseslint.configs.recommended,
{
rules: {
"no-console": "warn",
"eqeqeq": "error",
"@typescript-eslint/no-unused-vars": [
"error",
{ argsIgnorePattern: "^_" },
],
},
},
{
ignores: ["dist/**", "node_modules/**"],
}
);
Biome(biome.json)
// biome.json
{
"$schema": "https://biomejs.dev/schemas/1.9.0/schema.json",
"organizeImports": {
"enabled": true
},
"formatter": {
"enabled": true,
"indentStyle": "space",
"indentWidth": 2
},
"linter": {
"enabled": true,
"rules": {
"recommended": true,
"suspicious": {
"noConsole": "warn"
},
"style": {
"useConst": "error"
},
"correctness": {
"noUnusedVariables": "error"
}
}
},
"files": {
"ignore": ["dist/**", "node_modules/**"]
}
}
同じコードをリントする
以下の TypeScript ファイルを両ツールでチェックしてみます。
// src/example.ts
import { readFileSync } from "fs";
import { join } from "path";
import { tmpdir } from "os";
const getUserData = (id: number) => {
let name = "Alice";
var age = 30;
const unused = "this is never used";
if (id == 1) {
console.log("found user");
}
return { name, age };
};
export { getUserData };
ESLint の実行と出力
npx eslint src/example.ts
src/example.ts
1:1 warning 'readFileSync' is defined but never used @typescript-eslint/no-unused-vars
3:1 warning 'tmpdir' is defined but never used @typescript-eslint/no-unused-vars
8:3 error Unexpected var, use let or const instead no-var
9:9 error 'unused' is assigned but never used @typescript-eslint/no-unused-vars
11:7 error Expected '===' and instead saw '==' eqeqeq
12:5 warning Unexpected console statement no-console
✖ 6 problems (3 errors, 3 warnings)
Biome の実行と出力
npx biome check src/example.ts
src/example.ts:1:10 lint/correctness/noUnusedImports ━━━━━━━━━━━━━━━━━━━━━━━━━━
✖ This import is unused.
> 1 │ import { readFileSync } from "fs";
│ ^^^^^^^^^^^^
ℹ Safe fix: Remove the unused import.
src/example.ts:3:10 lint/correctness/noUnusedImports ━━━━━━━━━━━━━━━━━━━━━━━━━━
✖ This import is unused.
> 3 │ import { tmpdir } from "os";
│ ^^^^^^
src/example.ts:8:3 lint/style/noVar ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
✖ Use let or const instead of var.
> 8 │ var age = 30;
│ ^^^
ℹ Safe fix: Use 'let' instead.
src/example.ts:9:9 lint/correctness/noUnusedVariables ━━━━━━━━━━━━━━━━━━━━━━━━━
✖ This variable is unused.
> 9 │ const unused = "this is never used";
│ ^^^^^^
src/example.ts:11:7 lint/suspicious/noDoubleEquals ━━━━━━━━━━━━━━━━━━━━━━━━━━━━
✖ Use === instead of ==.
> 11 │ if (id == 1) {
│ ^^^^^^
ℹ Safe fix: Use ===.
src/example.ts:12:5 lint/suspicious/noConsole ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
⚠ Don't use console.
> 12 │ console.log("found user");
│ ^^^^^^^
Checked 1 file in 5ms. Found 6 diagnostics.
自動修正の比較
# ESLint の自動修正
npx eslint src/example.ts --fix
# Biome の自動修正(リント + フォーマット + インポート整理を一括)
npx biome check src/example.ts --write
Biome は --write 一発で、未使用インポートの削除・var → let への変換・== → === への変換・コードフォーマット・インポート整理をすべて実行します。
package.json スクリプトの比較
// ESLint + Prettier 構成
{
"scripts": {
"lint": "eslint .",
"lint:fix": "eslint . --fix",
"format": "prettier --write .",
"format:check": "prettier --check ."
}
}
// Biome 構成
{
"scripts": {
"lint": "biome check .",
"lint:fix": "biome check . --write",
"format": "biome format . --write",
"format:check": "biome format ."
}
}
5. どちらを選ぶべきか — ユースケース別の推奨
ESLint を選ぶべきケース
| ユースケース | 理由 |
|---|---|
| 既存の大規模プロジェクト | 移行コストが高く、既存の ESLint 設定資産を活かせる |
| 特殊なプラグインが必要 | eslint-plugin-react-hooks, eslint-plugin-jsx-a11y など Biome 未対応のルールがある |
| カスタムルールを自作したい | JavaScript でルールを書ける柔軟な API がある |
| Vue / Svelte / Angular | フレームワーク固有のプラグインが成熟している |
| チームが ESLint に慣れている | 学習コスト・移行コストを避けたい |
Biome を選ぶべきケース
| ユースケース | 理由 |
|---|---|
| 新規プロジェクト | ゼロコンフィグで始められ、ツール選定の手間が省ける |
| React / Next.js の TypeScript プロジェクト | 追加設定なしで TS + JSX を解析でき、速度も圧倒的 |
| ESLint + Prettier の競合に疲れた | リンターとフォーマッターが統合されており、競合が原理的に発生しない |
| CI の実行時間を短縮したい | 大規模リポジトリでも数秒で完了する |
| モノレポ | 単一バイナリで依存が少なく、インストールが高速 |
| 設定をシンプルに保ちたい | biome.json 1 ファイルですべて完結する |
段階的な移行(共存)
両者は共存可能です。まず Biome でフォーマッターを導入し、Prettier を置き換えてから、徐々にリントルールも移行するアプローチが現実的です。
# Prettier から Biome フォーマッターへの移行
npx biome migrate prettier --write
# ESLint から Biome リンターへの移行(対応ルールの確認)
npx biome migrate eslint --write
6. まとめ
| 判断軸 | 推奨 |
|---|---|
| エコシステムの広さ・柔軟性重視 | ESLint |
| 速度・シンプルさ・オールインワン重視 | Biome |
| 既存プロジェクトの維持 | ESLint(当面) |
| 新規プロジェクトの立ち上げ | Biome(まず試す価値あり) |