Oxlint integration
Oxlint is a Rust-based linter built on the oxc toolchain, offering large performance gains over ESLint. Since Oxlint implements "nearly all ESLint v9+ APIs" through its JS plugins feature, it can load eslint-plugin-boundaries directly.
This guide shows how to configure the plugin under Oxlint.
See the Oxlint integration example in the repository for a complete, runnable setup.
Compatibility
eslint-plugin-boundaries works under Oxlint's jsPlugins because it only relies on standard ESLint rule APIs, and needs neither of the two things Oxlint's JS plugins currently don't support:
- No custom parser — the plugin works on the AST that ESLint (or Oxlint, through its compatible API) already provides.
- No type-aware linting — classification and dependency checks are purely structural (file paths and import specifiers), not based on TypeScript types.
Oxlint builds its own internal module graph for multi-file analysis (used by rules like import/no-cycle). eslint-plugin-boundaries does not use that graph — like under ESLint, it resolves each import itself through the import/resolver setting (see below). This means it won't benefit from Oxlint's internal resolver cache, but it also means its behavior is consistent with how it works under ESLint.
Setup
Install Oxlint, the plugin, and a resolver for your path aliases:
npm install --save-dev oxlint eslint-plugin-boundaries eslint-import-resolver-typescript
Create an .oxlintrc.json file (or an oxlint.config.ts file — Oxlint supports both, see its configuration docs):
- .oxlintrc.json
- oxlint.config.ts
{
"jsPlugins": ["eslint-plugin-boundaries"],
"settings": {
"boundaries/include": ["src/**/*.ts"],
"boundaries/elements": [
{ "type": "helper", "pattern": "src/helpers/*" },
{ "type": "component", "pattern": "src/components/*" },
{ "type": "module", "pattern": "src/modules/*" }
],
"import/resolver": {
"typescript": {
"alwaysTryTypes": true
},
"node": true
}
},
"rules": {
"boundaries/no-unknown-dependencies": "error",
"boundaries/dependencies": ["error", {
"default": "disallow",
"policies": [
{
"from": { "element": { "type": "component" } },
"allow": { "to": { "element": { "type": "helper" } } }
},
{
"from": { "element": { "type": "module" } },
"allow": { "to": { "element": { "type": ["component", "helper"] } } }
}
]
}]
}
}
import { defineConfig } from "oxlint";
export default defineConfig({
jsPlugins: ["eslint-plugin-boundaries"],
settings: {
"boundaries/include": ["src/**/*.ts"],
"boundaries/elements": [
{ type: "helper", pattern: "src/helpers/*" },
{ type: "component", pattern: "src/components/*" },
{ type: "module", pattern: "src/modules/*" },
],
"import/resolver": {
typescript: { alwaysTryTypes: true },
node: true,
},
},
rules: {
"boundaries/no-unknown-dependencies": "error",
"boundaries/dependencies": ["error", {
default: "disallow",
policies: [
{ from: { element: { type: "component" } }, allow: { to: { element: { type: "helper" } } } },
{ from: { element: { type: "module" } }, allow: { to: { element: { type: ["component", "helper"] } } } },
],
}],
},
});
Then run Oxlint as usual:
npx oxlint
Set boundaries/include (and, if needed, boundaries/ignore) so only your source files are matched against element patterns. Without it, config files that Oxlint also lints as plain JavaScript (like a .cjs config file) can be reported as belonging to an unknown element by boundaries/no-unknown-files, since they don't match any of your descriptor patterns.
Findings and troubleshooting
These are the concrete issues found both in community reports and while building and running the example above.
The import/resolver setting is required
This is, by far, the most common source of problems (it was the root cause of the boundaries(no-unknown) error flood reported in the community).
eslint-plugin-boundaries doesn't resolve imports itself — like under ESLint, it delegates to the resolver chain configured in import/resolver. Oxlint activates no resolver by default (only its own internal import plugin, unrelated to import/resolver, has an implicit resolver). If you don't configure import/resolver, resolution falls back to plain Node.js path resolution, which cannot resolve extension-less TypeScript imports or tsconfig.json path aliases. In that case:
- A relative import that fails to resolve (e.g.
../../helpers/format-message) is classified as pointing to an unknown element, andboundaries/no-unknown-dependenciesreports it — if that rule is enabled. - A
tsconfig.jsonpath-alias import (e.g.@helpers/format-message) that fails to resolve looks like a bare module specifier, so it is silently reclassified as external (unresolvableAlias, seeboundaries/flag-as-external) — it does not raiseno-unknown-dependencies, and by default thedependenciesrule only evaluates local dependencies, so it silently skips boundary checks entirely instead of erroring.
Configuring import/resolver (as shown above) fixes both cases. See Custom Resolvers and TypeScript Support for the full resolver reference, and Debugging to inspect how each import is classified — debug mode works the same way under Oxlint:
ESLINT_PLUGIN_BOUNDARIES_DEBUG=1 oxlint
Referencing the plugin: package name matters
jsPlugins entries accept either a bare specifier string or an explicit alias object:
"jsPlugins": ["eslint-plugin-boundaries"]
"jsPlugins": [{ "name": "boundaries", "specifier": "eslint-plugin-boundaries" }]
Oxlint derives the rule namespace (boundaries in boundaries/dependencies) from the plugin's own package.json name field, not from the specifier text. This matters because the plugin is published under two names:
eslint-plugin-boundaries— itspackage.jsonnamematches the specifier, so the bare string form works out of the box: Oxlint strips theeslint-plugin-prefix and registers theboundariesnamespace.@boundaries/eslint-plugin— the scoped name doesn't have aneslint-plugin-prefix to strip, so the bare string form fails withPlugin 'boundaries' not found. Use the explicit alias form ({ "name": "boundaries", "specifier": "@boundaries/eslint-plugin" }) instead.
IDE vs. CLI differences
If linting works from the command line but not from an editor extension, it's usually because the extension runs Oxlint from a different working directory than your terminal. Set boundaries/root-path explicitly rather than relying on the process's current working directory, similar to the advice in Monorepo Setup.
Using the oxc resolver
eslint-import-resolver-oxc wraps oxc's own resolver and can be used as an import/resolver entry instead of eslint-import-resolver-typescript:
"import/resolver": {
"oxc": {
"tsconfig": {
"configFile": "./tsconfig.json",
"references": "auto"
}
}
}
This resolves imports through oxc's own resolver instead of the TypeScript compiler, which can be faster on large projects. See .oxlintrc.oxc.json in the example for this variant.
Migrating from ESLint
@oxlint/migrate converts an existing ESLint flat config to Oxlint automatically, and by default retains unsupported plugins — like eslint-plugin-boundaries — through jsPlugins. Your boundaries/* settings and rules carry over unchanged; only double-check the import/resolver setting made it into the generated config, per the finding above.
Further Reading
- Monorepo Setup - configuring the plugin across multiple packages.
- Custom Resolvers - the
import/resolversetting and available resolver packages. - TypeScript Support - the TypeScript resolver and path aliases.
- Debugging - inspect how each import is resolved and classified.