Skip to content

chore: migrate repo runtime linting from ESLint to oxlint#6928

Merged
aymeric-giraudet merged 5 commits intomasterfrom
codex/migrate-runtime-lint-to-oxlint
Mar 20, 2026
Merged

chore: migrate repo runtime linting from ESLint to oxlint#6928
aymeric-giraudet merged 5 commits intomasterfrom
codex/migrate-runtime-lint-to-oxlint

Conversation

@aymeric-giraudet
Copy link
Copy Markdown
Member

Summary

This migrates the repo runtime lint flow from ESLint to Oxlint.

The new setup keeps high-signal parity with our existing lint behavior, preserves our repo-specific restrictions through a local Oxlint plugin, and adds faster partial lint workflows for local development.

What changed

  • replaced the root lint runtime path with Oxlint
  • added shared .oxlintrc.json configs for the repo and relevant nested workspaces
  • added a local Oxlint JS plugin for our custom restricted-syntax rules
  • updated workspace lint scripts where they are still used locally
  • added:
    • yarn lint
    • yarn lint:ox <paths...>
    • yarn lint:changed
    • yarn lint:staged
    • yarn lint:bench
  • removed dead repo-level .eslintrc.js files
  • updated contributor docs to describe Oxlint + Prettier

Notes

  • this keeps Prettier as the formatter; we are not switching to oxfmt
  • eslint and eslint-plugin-import remain installed only because Oxlint still uses the JS-plugin fallback for import/order
  • template/example ESLint bits that are outside the repo runtime lint path were left in place intentionally
  • oxlint and oxlint-tsgolint are optional dependencies so environments that do not run lint do not fail on the Node engine requirement
  • lint environments now use Node 20.19.0 in local/CI tooling, while CodeSandbox keeps the valid major selector 20

Validation

Validated locally on March 16, 2026 with:

  • yarn build:ci
  • yarn lint
  • yarn type-check

CircleCI uses the same relevant gates, so this is aligned with CI behavior.

Benchmark

Recorded ESLint baseline from March 16, 2026:

  • yarn lint: 110.85s

Oxlint results from yarn lint:bench:

  • full lint mean: 9.19s
  • full lint median: 9.03s
  • full lint min: 8.94s

That is a 91.7% improvement over the recorded ESLint baseline.

Additional partial-run timings:

  • yarn lint:changed: mean 0.05s on the current branch state
  • yarn lint:ox packages/instantsearch.js: mean 1.74s

@codesandbox-ci
Copy link
Copy Markdown

codesandbox-ci Bot commented Mar 16, 2026

This pull request is automatically built and testable in CodeSandbox.

To see build info of the built libraries, click here or the icon next to each commit SHA.

Latest deployment of this branch, based on commit b500d8c:

Sandbox Source
example-instantsearch-getting-started Configuration
example-react-instantsearch-getting-started Configuration
example-react-instantsearch-next-app-dir-example Configuration
example-react-instantsearch-next-routing-example Configuration
example-vue-instantsearch-getting-started Configuration

@Haroenv
Copy link
Copy Markdown
Contributor

Haroenv commented Mar 16, 2026

does oxlint have a similar import order feature, even if the order is slightly different? could be nice to be able to drop eslint completely

@aymeric-giraudet
Copy link
Copy Markdown
Member Author

@Haroenv
I looked into that a bit: oxlint itself doesn’t have a full import/order equivalent today, but oxfmt does have import sorting that looks closer. I kept this PR scoped to replacing the lint runtime and intentionally left Prettier/formatting unchanged, so we don’t mix lint migration with a formatter change. If we want to fully drop the remaining ESLint compatibility dependency, I think the next step would be to evaluate oxfmt in a separate PR.

Copy link
Copy Markdown
Contributor

@Haroenv Haroenv left a comment

Choose a reason for hiding this comment

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

🔥 this looks very good! Are there any rules other than import formatting and the ones that are converted to a custom file that aren't compatible yet?

Comment thread packages/instantsearch-ui-components/src/lib/stickToBottom.ts Outdated
Comment thread scripts/lint/instantsearch-oxlint-plugin.mjs
Comment thread scripts/lint/benchmark.cjs Outdated
Comment thread scripts/lint/run-lint.cjs
Comment thread scripts/lint/instantsearch-oxlint-plugin.mjs
Copilot AI review requested due to automatic review settings March 18, 2026 13:56
@aymeric-giraudet
Copy link
Copy Markdown
Member Author

On the compatibility question: aside from import ordering and the repo-specific restrictions I moved into the local plugin, the remaining intentional drops are mostly legacy or style-only rules. Concretely, that is things like valid-jsdoc, strict, Vue SFC template/style rules that pure Oxlint cannot express, and a chunk of formatting-style rules inherited from eslint-config-algolia. The main correctness, suspicious, TS, React, import, and Jest coverage is otherwise preserved either natively or through Oxlint JS plugins.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR migrates the repository linting workflow from ESLint to Oxlint, introducing a shared .oxlintrc.json, custom Oxlint rules, and new scripts to run lint across the monorepo and selected file sets.

Changes:

  • Replace the root eslint-based lint scripts with scripts/lint/run-oxlint.cjs and scripts/lint/run-lint.cjs, and add Oxlint as optional dependencies.
  • Add a root .oxlintrc.json plus package-/folder-level .oxlintrc.json overrides, and introduce a custom instantsearch Oxlint plugin.
  • Update many files to comply with the new lint rules (type-only imports, void on floating promises, rule-name updates in eslint-disable comments, etc.), and update Node version references.

Reviewed changes

Copilot reviewed 76 out of 78 changed files in this pull request and generated 8 comments.

Show a summary per file
File Description
yarn.lock Locks new dependencies (notably Oxlint binaries/bindings).
tests/utils/matchers/vue.ts Updates lint-disable directives for global Jest namespace augmentation.
tests/utils/matchers/toWarnDev.ts Updates lint-disable directives for Jest matcher augmentation.
tests/utils/matchers/toMatchNormalizedInlineSnapshot.ts Updates lint-disable directives for Jest matcher augmentation.
tests/e2e/playwright/fixtures.ts Adjusts Playwright imports to use type import.
tests/common/.oxlintrc.json Adds test-level Oxlint overrides for Jest helpers.
specs/src/layouts/WidgetLayout.astro Reorders imports to satisfy import ordering.
specs/src/components/WidgetContent.astro Reorders imports to satisfy import ordering.
scripts/lint/run-oxlint.cjs Adds a CLI wrapper around Oxlint with changed/staged selection and workspace partitioning.
scripts/lint/run-lint.cjs Adds a higher-level lint runner orchestrating root + selected workspaces.
scripts/lint/instantsearch-oxlint-plugin.mjs Adds a custom Oxlint plugin (repo-specific rules).
scripts/.oxlintrc.json Adds script-folder Oxlint overrides (CommonJS + console allowed).
scripts/.eslintrc.js Removes legacy ESLint config for scripts.
packages/vue-instantsearch/src/tests/common-widgets.test.js Updates eslint-disable rule name for unused vars.
packages/vue-instantsearch/.storybook/config.js Reorders imports (and keeps Storybook setup intact).
packages/vue-instantsearch/.oxlintrc.json Adds Vue InstantSearch package-specific Oxlint overrides.
packages/vue-instantsearch/.eslintrc.js Removes legacy ESLint config for the package.
packages/react-instantsearch/src/widgets/Autocomplete.tsx Expands search-parameter typing to include hitsPerPage?.
packages/react-instantsearch/src/ui/tests/InfiniteHits.test.tsx Removes TypeScript non-null assertion in a querySelectorAll access.
packages/react-instantsearch-router-nextjs/src/index.ts Marks router push promise as intentionally ignored (void).
packages/react-instantsearch-core/src/lib/dequal.ts Updates lint-disable directives and restricted-syntax suppression for for..in.
packages/instantsearch.js/test/module/is-es-module.mjs Reorders imports to satisfy lint rules.
packages/instantsearch.js/test/module/is-cjs-module.cjs Reorders requires to satisfy lint rules.
packages/instantsearch.js/src/widgets/hits/defaultTemplates.ts Updates lint-disable directive for type-only imports.
packages/instantsearch.js/src/widgets/autocomplete/autocomplete.tsx Hardens getInputProps() spreading and simplifies event typing usage.
packages/instantsearch.js/src/widgets/analytics/analytics.ts Updates restricted-syntax suppression to custom instantsearch/no-for-in.
packages/instantsearch.js/src/middlewares/createInsightsMiddleware.ts Renames naming-convention disable to custom instantsearch/naming-convention.
packages/instantsearch.js/src/middlewares/tests/createMetadataMiddleware.ts Removes TypeScript non-null assertions around global.navigator.
packages/instantsearch.js/src/middlewares/tests/createInsightsMiddleware.ts Updates lint-disable directive for NodeJS namespace augmentation.
packages/instantsearch.js/src/lib/utils/logger.ts Updates eslint-disable rule name for unused vars.
packages/instantsearch.js/src/lib/utils/isEqual.ts Updates restricted-syntax suppression to custom instantsearch/no-for-of.
packages/instantsearch.js/src/lib/utils/checkIndexUiState.ts Removes TypeScript non-null assertions in widget name formatting.
packages/instantsearch.js/src/lib/utils/tests/hydrateSearchClient-composition-test.ts Marks returned promises as intentionally ignored (void).
packages/instantsearch.js/src/lib/utils/tests/debounce-test.ts Marks returned promises as intentionally ignored (void).
packages/instantsearch.js/src/lib/routers/history.ts Avoids window identifier in callback destructuring to comply with restrictions.
packages/instantsearch.js/src/lib/ai-lite/types.ts Switches naming-convention disable to custom instantsearch/naming-convention.
packages/instantsearch.js/src/lib/tests/server.test.ts Replaces non-null assertions with explicit runtime checks.
packages/instantsearch.js/src/connectors/numeric-menu/connectNumericMenu.ts Updates restricted-syntax suppression and slightly refactors refinement lookup.
packages/instantsearch.js/src/connectors/infinite-hits/connectInfiniteHitsWithInsights.ts Updates eslint-disable rule name for unused vars.
packages/instantsearch.js/src/connectors/hits/connectHitsWithInsights.ts Updates eslint-disable rule name for unused vars.
packages/instantsearch.js/.storybook/playgrounds/movies.ts Converts value import to type import.
packages/instantsearch.js/.storybook/playgrounds/default.ts Converts value imports to type imports.
packages/instantsearch.js/.storybook/decorators/withLifecycle.ts Converts value imports to type imports.
packages/instantsearch.js/.storybook/decorators/withHits.ts Splits and converts certain imports to type imports.
packages/instantsearch-ui-components/src/types/Renderer.ts Updates namespace lint-disable directive for JSX namespace setup.
packages/instantsearch-ui-components/src/components/chat/ChatMessages.tsx Marks clipboard promise as intentionally ignored (void).
packages/instantsearch-ui-components/src/components/tests/TrendingItems.test.tsx Removes TypeScript non-null assertion in a querySelectorAll access.
packages/instantsearch-ui-components/src/components/tests/RelatedProducts.test.tsx Removes TypeScript non-null assertion in a querySelectorAll access.
packages/instantsearch-ui-components/src/components/tests/LookingSimilar.test.tsx Removes TypeScript non-null assertion in a querySelectorAll access.
packages/instantsearch-ui-components/src/components/tests/Hits.test.tsx Removes TypeScript non-null assertion in a querySelectorAll access.
packages/instantsearch-ui-components/src/components/tests/FrequentlyBoughtTogether.test.tsx Removes TypeScript non-null assertion in a querySelectorAll access.
packages/instantsearch-ui-components/.oxlintrc.json Adds package-specific Oxlint overrides (notably no-unused-vars tuning).
packages/create-instantsearch-app/.oxlintrc.json Adds package-specific Oxlint overrides (CommonJS + console allowed).
packages/algoliasearch-helper/src/functions/merge.js Updates restricted-syntax suppression to custom instantsearch/no-for-in.
packages/algoliasearch-helper/package.json Switches package lint script from ESLint to Oxlint.
packages/algoliasearch-helper/index.d.ts Updates lint-disable directive for type-only import rule.
packages/algoliasearch-helper/.oxlintrc.json Adds helper-specific Oxlint overrides (ES5/CommonJS allowances).
package.json Replaces root lint scripts, removes some ESLint deps, adds Oxlint optional dependencies.
examples/vue/.oxlintrc.json Adds Vue example-specific Oxlint overrides.
examples/vue/.eslintrc.js Removes legacy ESLint config for Vue examples.
examples/react/ssr/.oxlintrc.json Adds SSR example-specific Oxlint overrides.
examples/react/ssr/.eslintrc.js Removes legacy ESLint config for SSR example.
examples/react/next/package.json Switches example lint script from ESLint to Oxlint.
examples/react/next/.oxlintrc.json Adds Next example ignore patterns.
examples/react/next-routing/package.json Switches example lint script from ESLint to Oxlint.
examples/react/next-routing/.oxlintrc.json Adds Next example ignore patterns.
examples/react/next-app-router/package.json Switches example lint script from ESLint to Oxlint.
examples/react/next-app-router/.oxlintrc.json Adds Next example ignore patterns.
examples/js/query-suggestions/package.json Switches example lint script from ESLint to Oxlint.
examples/js/getting-started/package.json Switches example lint script from ESLint to Oxlint.
examples/.oxlintrc.json Adds shared example-level Oxlint config + ignore patterns.
examples/.eslintrc.js Removes legacy ESLint config for examples.
CONTRIBUTING.md Updates contributor docs to describe the new lint workflow and commands.
.oxlintrc.json Adds the root Oxlint configuration (rules, plugins, overrides, custom plugin).
.nvmrc Updates Node version (20.10.0 → 20.19.0).
.eslintrc.js Removes legacy root ESLint config.
.eslintignore Updates ignore list (and preserves legacy ESLint ignores for reference/migration).
.circleci/config.yml Updates CI Node image version (20.10.0 → 20.19.0).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.

Comment thread tests/utils/matchers/vue.ts
Comment thread tests/utils/matchers/toWarnDev.ts
Comment thread tests/utils/matchers/toMatchNormalizedInlineSnapshot.ts
Comment thread packages/instantsearch-ui-components/src/types/Renderer.ts
Comment thread packages/react-instantsearch-core/src/lib/dequal.ts
Comment thread packages/instantsearch.js/src/widgets/hits/defaultTemplates.ts
Comment on lines +165 to +172

const result = spawnSync(oxlintBin, commandArgs, {
cwd,
stdio: 'inherit',
});

return result.status || 0;
}
@aymeric-giraudet aymeric-giraudet requested review from a team, FabienMotte and shaejaz and removed request for a team March 19, 2026 10:28
@aymeric-giraudet aymeric-giraudet merged commit d042c47 into master Mar 20, 2026
14 checks passed
@aymeric-giraudet aymeric-giraudet deleted the codex/migrate-runtime-lint-to-oxlint branch March 20, 2026 15:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants