Oxlint and Oxfmt configuration
If you already have an .oxlintrc.json or .oxfmtrc.json, it works here
unchanged. This page is the exact support matrix: which fields the native
commands honor, how a Vite+ config participates, and what fails loudly instead
of being silently ignored.
Configuration is loaded once when a
native session
starts and reused for every file in that batch. Ordinary .js, .jsx,
.ts, and .tsx files stay on the direct canonical path. Stock oxlint
and oxfmt still do not recognize .tsrx.
Installed through npm? You run the oxlint and oxfmt commands from
oxc-tsrx, and everything on
this page applies to them too. They can also take lint and fmt options
from a Vite+ vite.config.*; that contract is the
Vite+ configuration boundary.
The examples below invoke the native binaries directly because this page
documents the native boundary.
This is the whole resolution story in one picture. Select a node or step through the buttons:
The config examples on this page are annotated: hover any highlighted field name to read what the native boundary does with it.
Lint configuration#
oxc-tsrx searches upward from the working directory for one
.oxlintrc.json or .oxlintrc.jsonc, or takes an explicit JSON/JSONC file
with --config or -c. One config covers the whole batch; nested
per-directory discovery is not implemented yet.
The native boundary supports the following.
Config file fields:
- configured built-in rules and built-in plugins, including rule options;
env,globals, and built-in-pluginsettingsthrough canonicalConfigStoreBuilder;- JSON/JSONC
extends, resolved relative to the declaring config; - Vite+ object
extendsmaterialized through canonical OXC's publicextends_configsmodel; - per-file
overridesfor.tsrxand ordinary JS/JSX/TS/TSX paths; and ignorePatternsrooted at the config directory.
CLI flags and exit policy:
--allow/-A,--warn/-W, and--deny/-Dprecedence over configured severities; andoptions.denyWarningsandoptions.maxWarningsexit policy.
Output and fixes:
- explicit multi-file batches and identity-mapped
--fix; and - JSON diagnostic output at original TSRX byte spans.
Opt-in type lanes:
- official tsgolint rules through
--type-aware; and - TypeScript syntactic and semantic diagnostics through
--type-check.
Custom JavaScript plugins:
jsPluginson ordinary files and on.tsrx, through theoxlintcommand and the language server, with your own severities, rule options,extends, andoverridesresolved by Oxlint itself. SeejsPluginsand the two lanes for the extra parse this costs and the one command that still refuses it.
For example:
{
"plugins": ["react"],
"env": { "browser": true },
"globals": { "frameworkGlobal": "readonly" },
"rules": {
"no-debugger": "error",
"eqeqeq": ["error", "always"],
"react/jsx-no-undef": "error"
},
"overrides": [
{
"files": ["**/*.tsrx"],
"rules": { "no-console": "warn" }
}
],
"ignorePatterns": ["generated/**"]
}In the demo below, the discovered .oxlintrc.json (also passed as
config/lint.json) is this example plus the type-aware additions described in
the next section. src/View.tsrx has a console call, a debugger statement, a
wrong type annotation, and an unawaited call into src/service.tsrx.
# Discovered .oxlintrc.json: console is a warning, debugger an error oxc-tsrx --format=json src/View.tsrx src/View.tsx \ | jq '.diagnostics' [ { "filename": "src/View.tsrx", "rule": "no-console", "code": "eslint(no-console)", "severity": "warning", "message": "Unexpected console statement.", "labels": [ { "span": { "offset": 172, "length": 11 } } ] }, { "filename": "src/View.tsrx", "rule": "no-debugger", "code": "eslint(no-debugger)", "severity": "error", "message": "`debugger` statement is not allowed", "labels": [ { "span": { "offset": 204, "length": 9 } } ] }, { "filename": "src/View.tsx", "rule": "no-unused-vars", "code": "eslint(no-unused-vars)", "severity": "warning", "message": "Variable 'seen' is declared but never used. Unused variables should start with a '_'.", "labels": [ { "span": { "offset": 59, "length": 4 }, "message": "'seen' is declared here" } ] } ] # Explicit config path plus CLI severity overrides oxc-tsrx --format=json --config config/lint.json \ --warn no-console --deny no-debugger src/View.tsrx | jq '.diagnostics' [ { "filename": "src/View.tsrx", "rule": "no-console", "code": "eslint(no-console)", "severity": "warning", "message": "Unexpected console statement.", "labels": [ { "span": { "offset": 172, "length": 11 } } ] }, { "filename": "src/View.tsrx", "rule": "no-debugger", "code": "eslint(no-debugger)", "severity": "error", "message": "`debugger` statement is not allowed", "labels": [ { "span": { "offset": 204, "length": 9 } } ] } ] # One TypeScript-Go process covers the whole explicit batch; showing only what --type-aware adds oxc-tsrx --format=json --type-aware src/View.tsrx src/service.tsrx \ | jq '[.diagnostics[] | select(.code | startswith("typescript"))]' [ { "filename": "src/View.tsrx", "rule": "no-floating-promises", "code": "typescript(no-floating-promises)", "severity": "error", "message": "Promises must be awaited, add void operator to ignore.", "labels": [ { "span": { "offset": 216, "length": 12 } } ] } ] # --type-check additionally lands compiler diagnostics on your authored bytes; showing only those oxc-tsrx --format=json --type-check src/View.tsrx src/service.tsrx \ | jq '[.diagnostics[] | select(.code | startswith("typescript(TS"))]' [ { "filename": "src/View.tsrx", "rule": "parse-error", "code": "typescript(TS2322)", "severity": "error", "message": "Type 'string' is not assignable to type 'number'.", "labels": [ { "span": { "offset": 143, "length": 7 } } ] } ]
Type-aware linting#
The direct native command requires --type-aware or --type-check even when
the config contains options.typeAware or options.typeCheck. Config alone
fails actionably instead of unexpectedly starting a TypeScript-Go process.
--type-check implies the type-aware lane and additionally reports TypeScript
syntactic and semantic diagnostics. Through the npm toolchain, a resolved
Vite+ config forwards the corresponding explicit flag automatically.
{
"plugins": ["typescript"],
"rules": {
"typescript/no-floating-promises": "off"
},
"overrides": [
{
"files": ["**/*.tsrx"],
"rules": {
"typescript/no-floating-promises": "error"
}
}
],
"options": {
"typeAware": true,
"typeCheck": false
}
}In plain terms:
- The tool hands the type checker a temporary in-memory TSX copy of each
.tsrxfile, then maps every result back onto the bytes you actually wrote. Nothing is written to disk, and one tsgolint process covers the whole batch. - Rules and overrides are resolved against your authored
.tsrxpaths before that copy exists, so**/*.tsrxoverrides keep working. - A fix is only applied when the affected text exists verbatim in your authored file and the result reparses as valid TSRX.
The precise projection and fix-eligibility contract lives in Architecture.
Compiler diagnostics from --type-check use the same JSON shape as lint
diagnostics. A TypeScript compiler message has no lint rule name, so its
rule field falls back to parse-error while code carries the real
compiler code, such as typescript(TS2322).
Troubleshooting tsgolint discovery#
Type-aware runs need exactly oxlint-tsgolint 0.24.0, pinned through
oxc-tsrx's lint implementation dependency. When --type-aware or
--type-check fails to
start:
- Native discovery checks the project installation and
PATH. OXLINT_TSGOLINT_PATHselects an executable or its directory explicitly.- A standalone executable without package metadata also requires
OXC_TSRX_TSGOLINT_VERSION=0.24.0. - A missing binary, unverifiable binary, or version mismatch fails the command with exit status 2 instead of silently downgrading or writing source.
jsPlugins and the two lanes#
jsPlugins works on both halves of a project, but which command you run
decides whether it works at all, so it gets its own section.
- The
oxlintcommand and the language server run them on.tsrx. They build the legal-TSX projection of each.tsrxfile, run the published Oxlint binary over it with your own config, and map every diagnostic back onto your authored bytes. Ordinary files are untouched and go straight to canonical Oxlint. - That costs one extra parse per linted
.tsrxfile, and it is never silent.oxlintprints one line to stderr ahead of the report and repeats the fact in--format=jsonunderoxcTsrx.jsPluginProjection; the language server writes the same fact to its output log once per session. settings.oxcTsrx.jsPluginsOnTsrx: falseturns the lane off. Your plugins keep running on ordinary files. On.tsrxyou then get the refusal below instead of quietly fewer rules.- The direct native target refuses
jsPluginsand always did.oxc-tsrx-lintis a Rust process with no Node.js runtime, so it cannot host your module. It exits 2 with a message namingoxlintas the command that can.vp lintis not that target: it reaches this package through theoxlintcommand, so a Vite+ project keeps its plugins on both halves. See Vite and Vite+.
context.filename is the mirror path, @if and @for arrive already
compiled, and a diagnostic that lands on projected-only text is dropped. Those
are documented in full under Custom JavaScript
plugins.
Not yet supported#
These fail before a source parse or write; they are not silently disabled:
- JavaScript/TypeScript config modules passed to the direct native command.
- Alternate reporters and nested per-directory config discovery.
The direct native command accepts explicit source files and JSON output; the npm toolchain adds directory/glob arguments, combined default/JSON reporting, and ordinary-file delegation. Limitations tracks every remaining boundary.
Format configuration#
oxc-tsrx-fmt searches upward for one .oxfmtrc.json or
.oxfmtrc.jsonc. Pass an arbitrary JSON/JSONC config with --config or -c.
One FormatSession resolves the base options, overrides, and ignore matcher and
reuses them for stdin or every explicit file.
Supported JS/TSX options are:
useTabs,tabWidth,endOfLine, andprintWidth;singleQuote,jsxSingleQuote, andquoteProps;trailingComma,semi, andarrowParens;bracketSpacing,bracketSameLine, andobjectWrap;singleAttributePerLineandhtmlWhitespaceSensitivity; andinsertFinalNewline.
overrides, override excludeFiles, and ignorePatterns are supported.
Ordinary JS/TSX takes the canonical direct Oxfmt path with the same resolved
options. A .tsrx file uses the same options: the tool formats a temporary
TSX view of the file, then restores the TSRX syntax and verifies the result.
Transactional multi-file writes and raw <style>
payload byte preservation behave exactly as they do without a config file.
{
"singleQuote": true,
"semi": false,
"printWidth": 100,
"overrides": [
{
"files": ["**/*.tsrx"],
"options": { "singleAttributePerLine": true }
}
],
"ignorePatterns": ["generated/**"]
}In the demo below, the format configuration shown above is the discovered
.oxfmtrc.json and also config/format.json; both sample files still use
double quotes, so --check lists them. In the stdin output, the @{ }
statement container and the ; before <section> are intentional TSRX
syntax, not formatter damage.
# Both sample files differ from the configured single-quote layout oxc-tsrx-fmt --check src/View.tsrx src/View.tsx Checking formatting... src/View.tsrx (0ms) src/View.tsx (0ms) Format issues found in above 2 files. Run without `--check` to fix. Finished in 0ms on 2 files using 18 threads. # Rewrite one file with the explicit config; no file list means success oxc-tsrx-fmt --write --config config/format.json src/View.tsrx Finished in 0ms on 1 files using 18 threads. # Stdin mode prints the formatted source, single quotes and all oxc-tsrx-fmt --stdin-filepath=src/View.tsrx < src/View.tsrx /// <reference path="./jsx.d.ts" /> import { loadItems } from './service.tsrx' export function View({ label }: { label: string }) @{ const version: number = '0.1.0' console.log('render', label) debugger loadItems() ;<section class="view"> <h2>{label}</h2> <p>v{version}</p> </section> }
Not supported#
Enabled sortImports, sortTailwindcss, jsdoc,
embeddedLanguageFormatting, experimental formatter options, unknown
TSRX-affecting keys, .editorconfig, and JavaScript/TypeScript config modules
fail before output or writes. Oxfmt options that affect only non-JS languages,
such as package-JSON or prose formatting, do not change .tsrx output. Raw CSS
is preserved, not formatted or validated.
Performance evidence#
The retained release reports pin dedicated configuration invariants: one config load per session, unchanged parse counts and thresholds, and one tsgolint process per eligible type-aware batch. Benchmarks has the methodology, the full gate matrix, and the aggregate-selected reports.