Shareable oxlint + oxfmt configurations for TypeScript / React / Next.js / Backend / Tailwind / Test projects.
Strict by default. Composable via oxlint's native extends.
Browse the effective rules of every layer: https://oxc-config-preview.pages.dev
With Vite+ (vite-plus)
Vite+ bundles oxlint, oxfmt, and oxlint-tsgolint, so you only need to add this config (and any JS plugins you use):
pnpm add -D vite-plus @k8o/oxc-config
# Only when you use the matching lint layer:
pnpm add -D oxlint-tailwindcss # tailwind
pnpm add -D eslint-plugin-regexp # regexp
pnpm add -D @k8o/html-nest # html-nestpnpm add -D oxlint @k8o/oxc-config
# Add only what you actually use:
pnpm add -D oxfmt # if you use the `fmt` preset
pnpm add -D oxlint-tsgolint # type-aware rules (typescript / react / nextjs / backend)
pnpm add -D oxlint-tailwindcss # the `tailwind` layer
pnpm add -D eslint-plugin-regexp # the `regexp` layer
pnpm add -D @k8o/html-nest # the `html-nest` layer
pnpm add -D eslint-plugin-playwright # the `playwright` layer
pnpm add -D eslint-plugin-storybook storybook # the `storybook` layerRequires oxlint ≥ 1.71. The config enables rules that only exist in recent oxlint, and oxlint fails to build a config that references an unknown rule, so older versions are not supported. Node ≥ 24.13.
vp lint reads the lint: field of vite.config.ts, and vp fmt reads fmt:. Both accept the same shape as a standalone oxlint.config.ts / .oxfmtrc.json. Spread our presets in:
// vite.config.ts
import { defineConfig } from 'vite-plus';
import { fmt, nextjs, tailwind, test, TEST_GLOBS } from '@k8o/oxc-config';
export default defineConfig({
fmt,
lint: {
extends: [nextjs, tailwind],
options: {
reportUnusedDisableDirectives: 'error',
typeAware: true,
},
settings: {
react: { version: '19.0.0' },
},
overrides: [{ files: [...TEST_GLOBS], ...test }],
},
staged: {
'*.{js,ts,cjs,mjs,jsx,tsx,json,jsonc}': 'vp check --fix',
},
});package.json scripts:
Notes for Vite+ users:
- Don't install
oxlint,oxfmt, oroxlint-tsgolintdirectly — Vite+ wraps them. JS plugins (oxlint-tailwindcss,eslint-plugin-regexp, …) stay separate installs. - Type-aware rules work out of the box (no separate
oxlint-tsgolintinstall needed). vp checkruns format + lint + tsc together — recommended entry for CI.- The
vite.config.tsloader path thatvp lintuses is plain Node ESM (no TS transform). If you need to compose presets across files, keep it inline or build the consumer first.
// oxlint.config.ts
import { defineConfig } from 'oxlint';
import { nextjs, tailwind, test, TEST_GLOBS } from '@k8o/oxc-config';
export default defineConfig({
extends: [nextjs, tailwind],
options: {
reportUnusedDisableDirectives: 'error',
},
settings: {
react: { version: '19.0.0' },
},
overrides: [{ files: [...TEST_GLOBS], ...test }],
});For oxfmt, drop our fmt preset into a JS config, or use the generated JSON (below).
.oxlintrc.json's extends takes file paths, not npm specifiers (oxc#14413), so JSON consumers cannot import this package. We ship a generated JSON variant of each root lint layer (and the fmt preset) for exactly this case:
// .oxlintrc.json
{
"extends": ["./node_modules/@k8o/oxc-config/dist/nextjs.oxlintrc.json"],
}// .oxfmtrc.json — copy the generated preset, or reference the file in a JS config
// (dist/fmt.oxfmtrc.json)Available JSON layers: base, typescript, react, nextjs, backend, tailwind, regexp, html-nest (as dist/<layer>.oxlintrc.json), plus dist/fmt.oxfmtrc.json. The override-style layers (test, storybook, playwright) are applied via overrides, so JSON consumers copy their rule blocks into an overrides entry by hand.
base ─┬─ typescript ─┬─ react ── nextjs
│ └─ (stop at typescript for pure TS libs)
│
└─ backend
test (apply via overrides on test globs)
tailwind (compose with react / nextjs via extends)
regexp (compose with any layer via extends)
html-nest (compose with any JSX layer via extends)
storybook (apply via overrides on story globs)
playwright (apply via overrides on e2e globs)
fmt (oxfmt preset, independent of lint layers)
| Entry | Use for |
|---|---|
@k8o/oxc-config/base |
Lowest common denominator (plain JS) |
@k8o/oxc-config/typescript |
Pure TypeScript libraries / CLIs |
@k8o/oxc-config/react |
Any React app or library |
@k8o/oxc-config/nextjs |
Next.js App Router |
@k8o/oxc-config/backend |
Node, Cloudflare Workers, Hono |
@k8o/oxc-config/test |
Vitest test files (use in overrides) |
@k8o/oxc-config/tailwind |
Tailwind CSS v4 (composes with React / Next.js) |
@k8o/oxc-config/regexp |
Regex safety / ReDoS (composes with any layer) |
@k8o/oxc-config/html-nest |
HTML nesting validity in JSX (composes with react / nextjs) |
@k8o/oxc-config/storybook |
Storybook story files (use in overrides) |
@k8o/oxc-config/playwright |
Playwright e2e specs (use in overrides) |
@k8o/oxc-config/fmt |
oxfmt preset (single quotes, sort imports, …) |
Also exported: TEST_GLOBS, STORYBOOK_GLOBS, PLAYWRIGHT_GLOBS — canonical glob arrays for the overrides entries so you don't hand-copy (and drift from) the file matrix.
categoriesdeclared once — only inbase. Higher layers add specific rule overrides on top.- Files are pure deltas. Each layer lists only rules that differ from the category defaults (an off, a warn, a non-default option, or a cherry-pick). Rules that merely restate a category severity are not repeated — the snapshot suite guards against category drift.
nurseryis off. Leaving it at error silently escalates every new upstream nursery rule to an error on each oxlint minor bump.basesetsnursery: 'off'and cherry-picks the handful worth keeping.pluginsis replaced, not merged, by oxlint. Each layer lists every opt-in plugin it depends on (oxlint force-enableseslint/typescript/oxc/unicorn, so those are not listed).options.reportUnusedDisableDirectivesis root-only. Set it on the consumer's config, not on a shared layer.options.typeAware: truefromtypescriptonwards. Installoxlint-tsgolint(or use Vite+) to actually run those rules.
The typescript layer and everything above it set options.typeAware: true, which turns on oxlint-tsgolint (a typescript-go / TS7-based type checker). Caveats worth knowing:
- Standalone oxlint users must install
oxlint-tsgolint(it is an optional peer). Vite+ bundles it. - It runs a real type check, so it needs a resolvable
tsconfig.jsonand is meaningfully slower / more memory-hungry than the syntactic rules. - Its version is loosely coupled to oxlint's; when you bump oxlint, bump
oxlint-tsgolintin lockstep.
Pre-1.0 (0.x): treat any release as potentially breaking.
Because the categories are enabled wholesale, your effective rule set is also a function of the oxlint version you install, not just this package's version — upgrading your oxlint can surface new rules regardless of whether this package changed. To keep upgrades deliberate:
- Pin
oxlint/oxfmtexactly and bump them on purpose. - New rules this package adds ship as
minor; rule removals or severity bumps are called out in the changelog.
{ "scripts": { "lint": "vp lint", "fmt": "vp fmt", "check": "vp check", // = fmt + lint + tsc "check:write": "vp check --fix", }, }