コンテンツへスキップ
LatchkeyLatchkey home

Oxlint vs ESLint: CIにはどちらのJS linterか

Oxlint(Oxcプロジェクト由来)はESLintより桁違いに速く動作するRustベースのlinterで、ESLintは完全なルールとプラグインのエコシステムを保ちます。

ESLintは最大のルールとプラグインのセットを持つ標準的なJavaScript/TypeScriptのlinterです。OxlintはRustベースの速度重視のlinterで、ほぼゼロ設定で多くの一般的なルールをカバーし、時間とともにカバレッジを改善しています。

Oxlint vs ESLint at a glance

OxlintESLint
実装RustJavaScript
速度極めて高速より遅い
ルールカバレッジ多くの一般的なルール、成長中完全、最大
プラグインエコシステム限定的、成長中最大
設定ほぼゼロ柔軟
型を意識したlintあり。tsgo (TypeScript 7) 経由あり。typescript-eslint経由
設定形式独自設定、ESLint風v9とv10のflat config (eslint.config.js)
Autofixあり (--fix)あり (--fix)
エディタ統合利用可能普遍的
drop-inな置き換えまだ不可該当なし

CIでは

OxlintはESLintのごく一部の時間で巨大なコードベースをlintできるため、高速な第一段階のgateとして魅力的です。まだESLintのすべてのルールやプラグインをカバーしていないため、多くのチームは速度のためにOxlintを実行し、Oxlintに欠けているルールのためにESLintを残します - しばしばpushごとにOxlint、より完全なESLintパスをより低頻度で実行します。カスタムまたはframework固有のプラグインに依存する場合、ESLintは依然として不可欠です。

ESLint lint stepOxlint at 50xOxlint at 100x
10 seconds0.2 s0.1 s
60 seconds1.2 s0.6 s
3 minutes3.6 s1.8 s
8 minutes (large monorepo)9.6 s4.8 s

両者を併用する

Oxlintを高速な事前チェックとして、ESLintをそれがカバーしないルールのために実行します。lintはCPUバウンドなので特別なcacheは不要です。どちらもmanaged runnerで動作し、高速なmanaged runnerは大きなリポジトリでのESLintパスを短縮します。

  • What ports cleanly: core correctness rules, TypeScript rules, React hooks and JSX rules, and the common test-framework plugins.
  • What does not: your own in-house rules, and smaller community plugins nobody has ported.
  • Rule *names* mostly match ESLint, so disable comments and config intent carry over more easily than a rewrite would suggest.

型を意識したlintが最新かつ最大の変化

型を意識したルールとは、構文木だけでなく型チェッカーを必要とするものです。未処理のpromise、安全でない any の伝播、誤用されたpromiseなどです。従来これらはtypescript-eslint経由のESLint専用であり、完全な型チェックを要するためどの設定でも最も遅いルールでもありました。

  • oxlintはTypeScriptのGo移植 (tsgo、TypeScript 7) と統合することで型を意識したlintに対応し、未処理promiseの検出などが可能になりました。
  • これにより、TypeScriptのコードベースがoxlintをそもそも検討できなかった最大の技術的理由がなくなりました。
  • 同時にここは最も速く動いている領域なので、同等だと仮定せず、実際に依存しているルールに対する現在の対応状況を確認してください。

本当の障害: カスタムpluginがアルファ

社内ルールを保守しているなら、判断はこれで決まります。oxlintはESLintのpluginエコシステムと互換のJS pluginに対応していますが、その対応はアルファと明記されています。アルファはlintの実験には十分でも、マージを止めるゲートには不十分です。

  • カスタムルールがなく主流のpluginだけのリポジトリなら、今日でも移行できることが多いです。
  • アーキテクチャ上の制約を表現する社内ルールがあるリポジトリは、そのルールに限ってESLintを残すべきです。
  • ネイティブ (Rust) のpluginは安定していますが、Rustを書くことになり、JSのルールを保守するのとは別の話になります。

大規模リポジトリが実際に採る方法: 両方使う

どちらかを選ぶのではなく、oxlintを高速な事前フィルタとして走らせ、oxlintがまだ扱えないルールにESLintを使います。重要なところで速いフィードバックループを得つつ、必要なところで完全なルール網羅を保てます。

Running both, fast pass first
# package.json scripts
{
  "scripts": {
    "lint:fast": "oxlint",
    "lint:full": "eslint .",
    "lint": "oxlint && eslint ."
  }
}

# .github/workflows/ci.yml
jobs:
  lint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with: { node-version: 22, cache: npm }
      - run: npm ci
      # Fails in about a second on the 865 rules oxlint covers,
      # so the slow full pass only runs on code that already passes.
      - run: npx oxlint
      - run: npx eslint .

完全移行が理にかなう場合

  1. ESLintのpluginとカスタムルールを棚卸しし、それぞれをoxlintのルール一覧と突き合わせます。
  2. カスタムなものが出てこなければ、CIで数週間 oxlint をESLintと並走させ、検出結果を差分で比較します。
  3. 食い違いはすべて調べてください。同名のルールでも端の挙動が異なることがあり、その端こそ静かな挙動変化が潜む場所です。
  4. 信頼できたら高速なパスをpre-commitフックに移し、lint失敗がそもそもCIに届かないようにします。
  5. 差分が空になり、設定のどこもアルファのJS plugin対応に依存しなくなって初めて、ESLintを退役させてください。

The switching cost is mostly in the parts nobody lists

  • Assertions and mocks usually port mechanically when the target implements a compatible API; custom transformers and framework plugins do not.
  • Snapshot formats differ between runners, so plan to regenerate and review rather than port.
  • Run both suites in parallel in CI for a period and diff the results. A migration that changes which tests fail is not a migration, it is a regression you have not found yet.
  • Coverage numbers move on a runner change even when the tests do not, because instrumentation differs. Re-baseline any coverage gate deliberately.

The verdict

超高速なlintパスが欲しく、重要なルールがカバーされているなら: Oxlint(多くの場合ESLintと併用)。完全なルールとプラグインのエコシステムが必要なら: ESLint。多くのチームは両者を組み合わせます - 速度のためのOxlint、カバレッジのためのESLintです。

よくある質問

oxlintはESLintのdrop-inな置き換えですか?
まだです。865以上のルールを網羅し、ルール名もおおむねESLintと一致するため、主流の設定はよく移植できます。障害は、カスタムやニッチなコミュニティのルールが依存するJS pluginの対応がまだアルファであることです。社内ルールのないリポジトリは移行できることが多く、あるリポジトリはそのルールにESLintを残すべきです。
oxlintはESLintよりどれだけ速いですか?
公表されているベンチマークは50〜100倍です。実際には60秒のlintステップがおよそ1秒に、8分かかるmonorepoのlintが10秒未満になります。より大きな効果は質的なもので、1秒未満のlintは保存のたびにもpre-commitフックとしても実行でき、失敗がCIに届かなくなります。
oxlintは型を意識したlintに対応していますか?
はい。TypeScriptのGo移植 (tsgo、TypeScript 7) との統合を通じて対応しており、未処理promiseの検出などが有効になります。これは最近の機能で急速に動いているため、typescript-eslintと完全に同等だと仮定せず、依存している個別の型認識ルールの対応状況を確認してください。
oxlintにはいくつルールがありますか?
865以上で、ESLintのコアルール、TypeScriptのルール、React、Jest、Vitestを含む人気pluginのルールセットにまたがります。
oxlintとESLintを同時に使えますか?
はい、そしてそれが推奨される方法です。まず oxlint を走らせて違反の大半を約1秒で表面化させ、その後oxlintが扱わないルールのために eslint . を走らせます。網羅性を損なわずに失敗レイテンシが改善します。
本番でoxlintを使っているのは誰ですか?
Elastic Kibana、Sentry、Cloudflareが採用企業として挙げられています。いずれも大規模なコードベースであり、速度差が最も積み上がり、ESLintの完全なパスが最も苦痛になるケースです。
oxlintはautofixに対応していますか?
はい。eslint --fix と同じ形の oxlint --fix があります。はるかに高速なため、遅いESLintのパスではしばしば現実的でない「保存時のautofix」が実用になります。
既存のESLintのdisableコメントは効きますか?
おおむね効きます。oxlintが意図的にESLintのルール名に合わせているためです。とはいえ同名のルールでも端の挙動が異なり得るので、何かを退役させる前に一定期間並走させて検出結果を差分で確認してください。

関連ガイド