Shareable oxlint + oxfmt configurations for TypeScript / React / Next.js / Backend / Tailwind / Test projects.
Strict by default. Composable via oxlint's native extends.
With Vite+ (vite-plus)
Vite+ bundles oxlint, oxfmt, and oxlint-tsgolint, so you only need to add this config (and the optional Tailwind plugin):
pnpm add -D vite-plus @k8o/oxc-config
# Optional: only when you use the `tailwind` lint config
pnpm add -D oxlint-tailwindcss @oxlint/plugins@oxlint/plugins is a peer dep of oxlint-tailwindcss. Pin it to the same major version as the oxlint that ships inside your vite-plus (check with vp --version).
pnpm 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-tailwindcss # if you use the `tailwind` lint config
pnpm add -D oxlint-tsgolint # for type-aware rules (typescript / react / nextjs / backend)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 } 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.ts', '**/*.test.tsx'],
plugins: [...(test.plugins ?? [])],
rules: test.rules ?? {},
},
],
},
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.oxlint-tailwindcssis a JS plugin, so it stays a separate install. - 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 } from '@k8o/oxc-config';
export default defineConfig({
extends: [nextjs, tailwind],
options: {
reportUnusedDisableDirectives: 'error',
},
settings: {
react: { version: '19.0.0' },
},
overrides: [
{
files: ['**/*.test.ts', '**/*.test.tsx'],
plugins: [...(test.plugins ?? [])],
rules: test.rules ?? {},
},
],
});For oxfmt, drop our fmt preset into .oxfmtrc.json (or use oxfmt's defineConfig from a JS config file).
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)
fmt (oxfmt preset, independent of lint layers)
| Entry | Use for |
|---|---|
@k8o/oxc-config/base |
Lowest common denominator (no TS, no React) |
@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/fmt |
oxfmt preset (single quotes, sort imports, …) |
categoriesdeclared once — only inbase. Higher layers add specific rule overrides on top.pluginsis replaced, not merged, by oxlint. Each layer lists every plugin it depends on.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.
Pre-1.0 (0.x): treat any release as potentially breaking. Rule additions 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", }, }