Skip to content

feat(devops): add Oxlint alongside ESLint for incremental migration#3866

Draft
wraith4081 wants to merge 2 commits intoopenfrontio:mainfrom
wraith4081:feat/oxlint-migration
Draft

feat(devops): add Oxlint alongside ESLint for incremental migration#3866
wraith4081 wants to merge 2 commits intoopenfrontio:mainfrom
wraith4081:feat/oxlint-migration

Conversation

@wraith4081
Copy link
Copy Markdown
Contributor

Description:

Adds Oxlint to the project without removing ESLint yet.

This is intended as a first migration step: Oxlint now runs in local lint scripts, CI, lint-staged, and the pre-commit hook, while ESLint stays in place to keep the existing lint coverage unchanged.

Changes

  • Added oxlint and oxlint-tsgolint.
  • Added .oxlintrc.json.
  • Updated npm run lint and npm run lint:fix to run Oxlint first, then ESLint.
  • Added separate scripts for running Oxlint, ESLint, and GitHub-formatted lint output.
  • Updated the CI lint job to run both linters.
  • Updated lint-staged so Oxlint and ESLint only run on JS/TS files.
  • Made the Husky pre-commit hook run lint-staged sequentially to avoid linter/formatter races.
  • Updated docs to mention the Oxlint + ESLint transition.

Why not replace ESLint yet?

Oxlint looks promising and is much faster, but it is not a clean drop-in replacement for this repo yet.

When type-aware Oxlint defaults were enabled, it reported a lot of issues that our current ESLint setup does not enforce, including:

  • typescript/no-floating-promises
  • typescript/restrict-template-expressions
  • typescript/unbound-method
  • typescript/no-base-to-string

There were also a few behavior differences around no-unused-vars. (where Oxlint reported issues that the current ESLint setup does not fail on)

image

Because of that, this PR keeps ESLint as the safety net and only enables a small Oxlint rule set for now.

Current Oxlint rules

Oxlint’s default categories are disabled for now so this PR does not turn into a large unrelated lint cleanup.

Enabled rules:

  • typescript/prefer-nullish-coalescing
  • eqeqeq
  • no-case-declarations

ESLint still handles the existing recommended JS/TypeScript checks and current unused-var behavior.

Notes

  • oxlint-tsgolint is needed because typescript/prefer-nullish-coalescing is type-aware.
  • lint-staged only passes JS/TS files to Oxlint because Oxlint exits with an error when given unsupported files like Markdown.

Local timing

Initial local timings:

  • ESLint: 8.967s
  • Oxlint: 0.775s wall time (350ms reported by Oxlint over 474 files)

This is not a full parity benchmark yet, since Oxlint is currently running a smaller rule set, but it gives us a good reason to keep migrating rules over. (Ryzen 9 7940HS, 8x2 Thread, 40GB 4800MT/s DDR5, 990 Pro, Node v25.8.1)

Eslint Oxlint
image image

Please complete the following:

  • I have added screenshots for all UI updates
  • I process any text displayed to the user through translateText() and I've added it to the en.json file
  • I have added relevant tests to the test directory
  • I confirm I have thoroughly tested these changes and take full responsibility for any bugs introduced

Please put your Discord username so you can be contacted if a bug or regression is found:

wraith4081

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 6, 2026

Walkthrough

Oxlint is integrated as a primary linter alongside ESLint through configuration, package scripts, CI workflow updates, and pre-commit hook adjustments. Documentation is updated to reflect the linting infrastructure changes.

Changes

Linting Infrastructure Setup

Layer / File(s) Summary
Linting Configuration
.oxlintrc.json
New Oxlint config file enables browser and node environments, disables all lint categories by default, enables type-aware linting, and configures specific rules for prefer-nullish-coalescing, eqeqeq, no-case-declarations, no-explicit-any, and no-unused-vars.
Package Scripts & Dependencies
package.json
Seven new lint scripts (lint, lint:fix, lint:oxlint, lint:oxlint:fix, lint:github, lint:eslint, lint:eslint:fix) are added. DevDependencies oxlint and oxlint-tsgolint are introduced. Lint-staged is expanded to run oxlint and eslint on JS/TS files and prettier on all files.
CI Workflow
.github/workflows/ci.yml
Lint step renamed and command updated from direct ESLint invocation to npm run lint:github script.
Pre-commit Hook
.husky/pre-commit
Lint-staged invocation adds --concurrent false flag to disable concurrent execution.
Documentation
CLAUDE.md, CONTRIBUTING.md, README.md
Docs updated to document Oxlint integration: CLAUDE.md updates lint command descriptions, CONTRIBUTING.md adds migration note, README.md adds subsection for Oxlint and ESLint linting workflow.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Poem

Oxlint arrives with its steady gaze,
checking our code through configuration's maze,
pre-commit guards watch with concurrent care,
while scripts and workflows all play their fair share. ✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately reflects the main change: adding Oxlint alongside ESLint for an incremental migration strategy, which is clearly the primary objective across all modified files.
Description check ✅ Passed The description comprehensively explains the changes, rationale, and implementation details related to the Oxlint integration, directly matching the changeset across all files.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@socket-security
Copy link
Copy Markdown

socket-security Bot commented May 6, 2026

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Addednpm/​oxlint@​1.63.0991009195100
Addednpm/​oxlint-tsgolint@​0.22.11001009795100

View full report

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
package.json (1)

23-23: ⚡ Quick win

Run both linters in lint:github, even if one fails.

Using && stops at the first failing linter, so ESLint results can be hidden in the same CI run. That weakens the migration safety-net feedback loop.

Proposed change
-    "lint:github": "oxlint --format=github && eslint --format gha",
+    "lint:github": "concurrently --success=all \"oxlint --format=github\" \"eslint --format gha\"",
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@package.json` at line 23, The lint:github npm script currently uses `&&`
which stops at the first failure; update the "lint:github" script so it runs
both linters regardless of the first exit code and then returns a non-zero exit
code if either failed (for example, run oxlint then eslint sequentially
capturing each exit status and exit with a non-zero code if either failed).
Modify the "lint:github" script entry in package.json (the script key
"lint:github") to implement this behavior so both linters always run but the CI
still fails when any linter fails.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@package.json`:
- Line 23: The lint:github npm script currently uses `&&` which stops at the
first failure; update the "lint:github" script so it runs both linters
regardless of the first exit code and then returns a non-zero exit code if
either failed (for example, run oxlint then eslint sequentially capturing each
exit status and exit with a non-zero code if either failed). Modify the
"lint:github" script entry in package.json (the script key "lint:github") to
implement this behavior so both linters always run but the CI still fails when
any linter fails.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 4a943748-8fe8-4c21-b3d3-8ad1e98c5cdc

📥 Commits

Reviewing files that changed from the base of the PR and between 23b8eaa and 1c18141.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (7)
  • .github/workflows/ci.yml
  • .husky/pre-commit
  • .oxlintrc.json
  • CLAUDE.md
  • CONTRIBUTING.md
  • README.md
  • package.json

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Triage

Development

Successfully merging this pull request may close these issues.

1 participant