Getting Started
Everything ships in one package, oxc-tsrx. It gives you the oxlint and
oxfmt commands you already know, now handling .tsrx files, plus a parser
API, a language server, and support for your own
custom JavaScript lint plugins.
It does not compile anything. Building and running .tsrx is your framework's
TSRX plugin's job, and you install that separately from
tsrx.dev/getting-started (opens in new tab). The two are
independent: this package never touches your build or dev server.
Install#
You need Node.js 20.19 or newer. Install one dev dependency:
npm install --save-dev oxc-tsrx@latestpnpm add -D oxc-tsrx@latestyarn add -D oxc-tsrx@latestbun add -d oxc-tsrx@latestThat is the whole setup. The tools are Rust, but you get a prebuilt binary for your platform: no Rust needed, no install scripts, nothing fetched later. It works on CI that blocks postinstall.
Eight platforms have binaries. Platform Support says which is yours and how well tested it is.
The minimum steps, per host#
This is the complete list of things you have to run to lint and format .tsrx.
| Where you use it | Steps | What you run |
|---|---|---|
Command line (oxlint, oxfmt) |
1 | npm install --save-dev oxc-tsrx@latest |
| Editor, through the released official OXC extension | 1 | the same install, and nothing else |
Vite+ (vp lint, vp fmt) |
2 | the same install, then oxc-tsrx setup |
No row asks you to create a config file, add an ignore file, or add a lifecycle
script. oxc-tsrx writes nothing into your project during install.
Making TSRX a language in your editor belongs to the TSRX toolchain, not to
this package. It needs @tsrx/typescript-plugin, a framework binding, and a
plugins entry in the tsconfig that owns your source. setup reports all
three and installs none.
Custom JavaScript plugins
walks the sequence on a fresh scaffold.
What the install adds to node_modules/.bin#
Three commands are yours to type:
| Command | What it is |
|---|---|
oxlint |
the linter. Handles .tsrx plus ordinary files |
oxfmt |
the formatter. Same split |
oxc-tsrx |
providers, status, setup, and remove. See the CLI reference |
Four more get linked that you never type: three native leaf commands, plus
tsgolint from a dependency.
- Not Node-only. npm, pnpm, yarn, and bun are covered in CI, and Deno works
but is not. Only the wrappers need Node; the linter and formatter are one
standalone binary at
node_modules/@oxc-tsrx/native-<your-platform>/bin/oxc-tsrx. - Except under Vite+, where
oxlintandoxfmtare Vite+'s wrappers rather than ours. Usevp lintandvp fmt.
To see what a host finds in your project, without changing anything:
npx oxc-tsrx providers --jsonThe line to look for is routed extensions: .tsrx -> oxc-tsrx. (Don't be
alarmed if npx oxc-tsrx status prints missing three times outside a Vite+
project. That is the correct result, and
Limitations says why.)
Editors need no extra install#
Install oxc-tsrx and nothing else, and the released official OXC extension
gives you .tsrx diagnostics that refresh as you type, formatting, quick fixes
you can apply, and your own Oxlint JavaScript plugin rules. Ordinary TypeScript
files keep going to canonical Oxlint.
One step is not an install, and skipping it looks like a broken integration.
The official extension never activates on .tsrx. Open any JavaScript,
TypeScript, or JSON file once, and .tsrx is served for the rest of the
session. See
the editor page
for what that session covered.
Using Vite+? (compatibility step)#
Released Vite+ finds its lint and format tools
through project-local packages named literally oxlint and oxfmt. A command
name cannot satisfy that, and this project cannot legitimately publish a package
under either name, so Vite+ needs the project-local slots that
oxc-tsrx setup writes:
npm install --save-dev vite-plus oxc-tsrx@latest
npx oxc-tsrx setuppnpm add -D vite-plus oxc-tsrx@latest
pnpm exec oxc-tsrx setupyarn add -D vite-plus oxc-tsrx@latest
yarn oxc-tsrx setupbun add -d vite-plus oxc-tsrx@latest
bunx oxc-tsrx setupPick your own package manager in the tabs above and run both lines with it. In a
project vp create scaffolded, that is almost never the npm tab: vp create
writes a devEngines.packageManager block into package.json naming pnpm, and
npm then refuses to run there at all.
setup is explicit, idempotent, reversible, and never edits package.json. It
works inside node_modules, so run it again after every clean dependency
install.
After that, vp lint, vp fmt, and vp check --fix handle .tsrx. If your
scaffold turns type-aware lint on, add one more dependency first: Vite+ and
this package can disagree about which oxlint-tsgolint runs.
The type-aware template default
has the failure, the fix, and the alternative.
Vite+ is the only place an install alone is not enough.
Create a TSRX file#
Save this as src/Cart.tsrx. On this site, the "Try in playground" button
under the snippet lets you explore it in your browser without installing
anything. The var total and debugger lines are there on purpose: they
give the linter something to catch.
export function Cart({ items }: Props) @{
var total = 0;
debugger;
<section class="cart">
@if (items.length > 0) {
@for (const item of items; key item.id) {
<Row item={item} />
}
} @else {
<Empty />
}
</section>
}Lint and format it#
Run the linter, then ask the formatter which files would change. This is a recording of both commands running against this exact file:
npx oxlint src/Cart.tsrx src/Cart.tsrx:2:7: warning eslint(no-unused-vars): Variable 'total' is declared but never used. Unused variables should start with a '_'. src/Cart.tsrx:3:3: warning eslint(no-debugger): `debugger` statement is not allowed Found 0 error(s) and 2 warning(s). npx oxfmt --check src/Cart.tsrx Checking formatting... src/Cart.tsrx (0ms) Format issues found in above 1 files. Run without `--check` to fix. Finished in 0ms on 1 files using 18 threads.
Every diagnostic points at line and column numbers in your original TSRX code, never at a transformed copy. Once you have fixed the warnings, let the formatter write its layout changes:
# The warnings are fixed, but look at the spacing cat src/Cart.tsrx export function Cart({items}:Props) @{ <section class="cart"> @if (items.length>0) { @for (const item of items; key item.id) { <Row item={item}/> } } @else { <Empty/> } </section> } # Rewrite the file in place; a summary line and no file list means it worked npx oxfmt --write src/Cart.tsrx Finished in 0ms on 1 files using 18 threads. # Same file, now in canonical Oxfmt layout cat src/Cart.tsrx export function Cart({ items }: Props) @{ <section class="cart"> @if (items.length > 0) { @for (const item of items; key item.id) { <Row item={item} />; } } @else { <Empty />; } </section>; }
Two things to know:
- Mixed file types are fine.
.tsrxfiles go through the TSRX engine, while ordinary.js/.ts/.tsxfiles go straight to OXC. - You can tune rule severity inline. For example
npx oxlint --warn no-console --deny no-debugger src/Cart.tsrx.
Give the linter a path, or an empty folder will bury you#
npx oxlint with no path lints everything under the current directory,
node_modules included. That is canonical Oxlint behavior, not something TSRX
adds. Two things avoid it:
- A
.gitignorelistingnode_modules. Oxlint honors it even outside a git repository. Real projects have one; fresh scratch folders do not, which is the only place this bites. - Naming a path.
npx oxlint srclints your sources and nothing else.
This package ships no ignore file and no config, and writes none. Your
.gitignore and .oxlintrc.json are the only inputs.
Do not run
npx oxlint --fixwherenode_modulesis still in scope. With nothing narrowing the run,--fixrewrites files inside your dependency tree and still exits 0. Official Oxlint does the same, so this is upstream parity rather than a TSRX defect, but your dependency tree is modified either way. Fix a path you own (npx oxlint --fix src), or make surenode_modulesis ignored first.
oxfmt is not affected. It skips node_modules unless you pass
--with-node-modules.
Configuration#
Both commands find your normal OXC config by searching upward from the
current directory (.oxlintrc.json/.oxlintrc.jsonc for lint,
.oxfmtrc.json/.oxfmtrc.jsonc for format), or take an explicit
--config/-c path. See
Configuration for exactly which fields
are supported.
Build from source (optional)#
If you would rather build the native binaries yourself, you need a stable Rust toolchain (rustup (opens in new tab)):
git clone https://github.com/markless-dev/oxc-tsrx.git
cd oxc-tsrx
cargo build --release --locked -p oxc_tsrx_cli --binsKeep the --locked flag: it makes Cargo build against the exact pinned OXC
commit from the lockfile. The binaries land in target/release/:
# The report is one line of JSON; jq picks out the diagnostics target/release/oxc-tsrx --format=json src/Cart.tsrx | jq '.diagnostics' [ { "filename": "src/Cart.tsrx", "rule": "no-unused-vars", "code": "eslint(no-unused-vars)", "severity": "warning", "message": "Variable 'total' is declared but never used. Unused variables should start with a '_'.", "labels": [ { "span": { "offset": 48, "length": 5 }, "message": "'total' is declared here" } ] }, { "filename": "src/Cart.tsrx", "rule": "no-debugger", "code": "eslint(no-debugger)", "severity": "warning", "message": "`debugger` statement is not allowed", "labels": [ { "span": { "offset": 61, "length": 9 } } ] } ] # And the metadata proves it parsed your file exactly once target/release/oxc-tsrx --format=json src/Cart.tsrx | jq '.oxcTsrx.parseCount' 1
The native binaries emit JSON diagnostics and want explicit file paths. The friendly text output, directory walking, and glob handling come from the npm commands, so most projects only need those. See the CLI Reference for every flag.
Next steps#
- See which TSRX syntax is supported in TSRX Syntax.
- Keep your framework's TSRX plugin as-is; it compiles and runs
.tsrx. See tsrx.dev (opens in new tab) for it, and Vite and Vite+ for how the two sit side by side. - Get live diagnostics, formatting, and quick fixes through the official OXC extension with Editor integration.
- Curious how it works under the hood? Read Architecture.