Nested configuration files
Oxlint can use multiple configuration files in the same repository. It automatically detects configuration files named .oxlintrc.json, .oxlintrc.jsonc, oxlint.config.ts, or oxlint.config.mts and applies them based on where files live in the directory tree.
This is useful in monorepos where packages need their own settings, while still keeping a shared baseline.
If you only need to exclude files or folders, use Ignores instead.
How it works
For each file being linted, Oxlint uses the nearest config file (e.g. .oxlintrc.json or oxlint.config.ts) relative to that file.
Given the following structure:
my-project/
├── .oxlintrc.json
├── src/
│ ├── index.js
├── package1/
│ ├── oxlint.config.ts
│ └── index.js
└── package2/
├── .oxlintrc.json
└── index.jsConfiguration resolution works as follows:
src/index.jsusesmy-project/.oxlintrc.jsonpackage1/index.jsusesmy-project/package1/oxlint.config.tspackage2/index.jsusesmy-project/package2/.oxlintrc.json
What to expect
Configuration files are not automatically merged. A config in a child directory does not affect the parent config.
Command line options override configuration files, regardless of whether they come from a parent or child directory.
Passing an explicit config file location using -c or --config disables nested config lookup, and Oxlint will only use that single configuration file.
You can also disable nested configs with the --disable-nested-config flag.
Linter options in nested configs
Most options are resolved from the config that governs the file:
options.typeAware— type-aware linting is enabled only for the files the config governs. This lets a single package in a monorepo opt into type-aware rules without slowing down the rest of the repository.options.reportUnusedDisableDirectivesoptions.respectEslintDisableDirectives
These options are not inherited from the root config. An option a config does not set takes its default, so a file is linted the same way whether you open the repository root or the package folder on its own, and whether CI runs Oxlint from the root or from the package. To share an option across packages, put it in a config the package files extends; a package config can still override it.
CLI flags and editor settings take precedence over every config, and apply to every file. oxlint --type-aware runs type-aware linting on the whole repository, including the packages whose config does not set options.typeAware.
WARNING
A nested config that enables type-aware rules without setting options.typeAware — and without extending a config that does — runs none of them. Oxlint prints a warning naming the rules when this happens.
Two options cannot be scoped to a directory:
options.denyWarningsandoptions.maxWarningsdecide the exit code of the whole run. They are only supported in the root config. Setting either in a nested config prints a warning and ignores that option; the rest of the config still applies.options.typeCheckis reported per run bytsgolint, not per directory. Setting it in a nested config enables type checking for the whole run, and prints a warning saying so. It belongs in the root config.
Type-aware linting for a single package
my-project/
├── .oxlintrc.json
├── package1/
│ ├── .oxlintrc.json
│ └── index.ts
└── package2/
└── index.ts{
"rules": {
"no-debugger": "error"
}
}{
"extends": ["../.oxlintrc.json"],
"plugins": [],
"options": {
"typeAware": true
},
"rules": {
"typescript/no-floating-promises": "error"
}
}package1/index.ts is linted with type-aware rules, package2/index.ts is not.
For the opposite — type-aware everywhere except one package — move "options": { "typeAware": true } into my-project/.oxlintrc.json, give every package a config that extends it, and turn the option off in the one package that should opt out:
{
"extends": ["../.oxlintrc.json"],
"plugins": [],
"options": {
"typeAware": false
}
}Monorepo pattern: share a base config with extends
In a monorepo, you often want one shared baseline at the root, and small package specific adjustments.
You do this by keeping a root config file (either .oxlintrc.json or oxlint.config.ts), then having package configs extend it.
{
"rules": {
"no-debugger": "error"
}
}import { defineConfig } from "oxlint";
export default defineConfig({
rules: {
"no-debugger": "error",
},
});{
"extends": ["../.oxlintrc.json"],
"rules": {
"no-console": "off"
}
}import baseConfig from "../oxlint.config.ts";
import { defineConfig } from "oxlint";
export default defineConfig({
extends: [baseConfig],
rules: {
"no-console": "off",
},
});This keeps the shared baseline in one place and makes package configs small and focused.
Extending configuration files
A config can reuse settings from other configs using extends.
In .oxlintrc.json, extends is an array of file paths, resolved relative to the config file that declares them. Extended files can have any name. They do not need to be named .oxlintrc.json, as long as they are valid JSON configuration files. Package imports are not supported in the .oxlintrc.json format.
In oxlint.config.ts, import the config objects you want to extend and pass them to extends (file paths are not supported). The imported files can have any name; only the entry config that Oxlint loads must be auto-discoverable (oxlint.config.ts or oxlint.config.mts) or passed via --config. Use a TypeScript config when extending config objects imported from a shared package.
Example:
{
"plugins": ["typescript"],
"rules": {
"typescript/no-explicit-any": "error"
}
}import { defineConfig } from "oxlint";
export default defineConfig({
plugins: ["typescript"],
rules: {
"typescript/no-explicit-any": "error",
},
});{
"extends": ["oxlint-typescript.json"],
"rules": {
"no-unused-vars": "warn"
}
}import typescriptConfig from "./oxlint-typescript.config.ts";
import { defineConfig } from "oxlint";
export default defineConfig({
extends: [typescriptConfig],
rules: {
"no-unused-vars": "warn",
},
});Shared packages work the same way in oxlint.config.ts:
import sharedConfig from "@example-org/oxlint-config";
import { defineConfig } from "oxlint";
export default defineConfig({
extends: [sharedConfig],
});Only some properties can be extended. The supported properties are:
rulespluginsoverrides
How plugins merges
Each config in an extends chain contributes its plugins list, and the result is the union of all contributions. A config that does not declare plugins contributes the default plugins instead.
This means extending a config with a narrower plugins list than the defaults is not enough on its own: if the extending config omits plugins, the defaults are added back on top of the extended list.
To inherit exactly the plugins of the extended config, declare an empty array:
{
"extends": ["./base.json"],
"plugins": []
}import baseConfig from "./base.config.ts";
import { defineConfig } from "oxlint";
export default defineConfig({
extends: [baseConfig],
plugins: [],
});The empty array is an empty contribution, so the result is exactly the plugins declared by base.json. Declaring a non-empty list works the same way: the union of that list and the extended lists, with the defaults only appearing if some config in the chain omits plugins.
This is the same mechanism as disabling the default plugins with "plugins": [] in a standalone config: an explicit array replaces the config's default contribution.
