oxvg and the Rust rewrite of the SVG toolchain
Fastest SVG toolchain for optimisation, minification, linting, and actions. Usable via CLI, Node, Wasm, or Rust.
At a glance
- What is it?
- oxvg is a Rust SVG toolchain that bundles an SVGO-derived optimiser, a linter, a scripting action system and a JSX transformer, published as a CLI, a Node native addon, a WASM package and a set of Rust crates. It is pre-1.0 at version 0.0.9, and its own documentation is candid about where it diverges from SVGO.
- Who is it for?
- oxvg fits a team that ships a lot of SVG and wants a single fast binary for optimisation, linting and JSX generation, and that is willing to follow a project moving quickly under a 0.0.x version.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 2 days ago.
- What is it written in?
- Mainly Rust, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.
Editorial analysis
One toolchain, four ways to reach it
oxvg is described as the fastest SVG toolchain for optimisation, minification, linting and actions, usable via CLI and libraries for Node, WASM or Rust. The repository layout makes the shape clear: a `crates/` directory holding the Rust libraries, a `packages/` directory holding the bindings, plus `biome.json` and a pnpm workspace at the root.
The Cargo workspace members are `crates/*` plus `packages/wasm`, `packages/napi` and `packages/jsx`, so the bindings are part of the same build rather than separate projects. The published npm package is `@oxvg/oxvg` at the same 0.0.9 version as the crate, and the readme links separate npm packages for the Node addon at `@oxvg/napi` and the WASM build at `@oxvg/wasm`, and a crates.io user page for the Rust side.
That four-way distribution is a real design decision rather than a packaging detail. A build tool that is a native binary is fast but has to be installed on every machine and in every CI image. The Node addon sits in the dependency tree of an existing JavaScript project. The WASM build runs anywhere JavaScript runs, including in a browser, which is what makes the OXVGUI playground in a browser possible. And the crates let a Rust project use the same code without shelling out to anything.
The claim about speed is qualified in the footnote, which says fastest I am aware of, with a link to the benchmarks wiki page, and the optimiser section says it can run up to 50x faster especially on larger file-sets. The mechanism behind that number is not described in the readme, so the honest reading is that the comparison is against SVGO and that the advantage grows with the size of the file set, which is what you would expect from a difference in the parser and serialiser rather than in the individual plugins.
The optimiser is SVGO derived, and the differences are documented
The optimiser is the piece most teams would care about, and the readme is unusually straightforward about its relationship to the tool everyone already uses.
An SVG optimiser similar to SVGO is available, and the project based the optimiser on SVGO and aims for compatibility with it, but it isn't a 1-for-1 replacement. As a result, some plugins may behave differently, and there is an SVGO parity guide to understand the differences and instructions for migrating an existing configuration.
That guide link is the important detail. Migrating an SVGO setup is a known, bounded task rather than an open question, and the existence of a parity guide is what makes the claim credible. A tool that simply said it was compatible would be worth very little; a tool that says it is not a one-for-one replacement and points at a guide is telling you the real cost.
The usage is a filter, and the command is short:
oxvg optimise < input.svg > output.svgwith `oxvg optimize` given as an alternative spelling, and the pipe form shown as `cat my-file.svg | oxvg optimise > my-file.optimised.svg`.
The readme also points to OXVGUI, a simple web-based playground built by Jonas Geiler where you can try the optimiser in the browser, which is the WASM build in front of a UI.
There is one more piece of external validation in the acknowledgements: Parcel, for choosing OXVG as a default optimiser. A bundler adopting a 0.0.x project as its default is a strong signal about the output quality, because a default optimiser processes every SVG anyone builds with Parcel, and SVGO's own defaults are what it is being compared against.
Actions, linter and JSX are three separate tools, not plugins
The CLI carries three distinct tool families, and they are separate in a way that is worth understanding.
Actions are a set of commands invoked by a program in order to manipulate an SVG document or pull information from it, and the readme compares them to Inkscape's actions but without any dependency on the UI or rendering. The example is a path intersection:
cat overlapping-paths.svg | oxvg action -- -select path -path-intersect > merged-paths.svgThe `--` separator and the `-select path` style arguments make this a command language rather than a plugin configuration, which is the difference from the SVGO model where plugins are configured declaratively in a JavaScript file.
The linter is described as basic, similar to svglint or vnu, and it can report SVG issues directly from the command line or through its language-server integration:
# Start language-server
oxvg lint serve
# Report diagnostics to stderr
oxvg lint check w3c/ -rA language server for an asset format is an unusual and genuinely useful feature. An SVG in a repository is usually checked by a linter that knows about SVG as a file, and a language server means the same diagnostics surface in the editor, so a designer editing an icon file sees the problem while they type it.
The JSX transformer takes SVG documents and transforms them into JSX components for use in React, Preact, Native or any other JSX-compatible language, and it aims to implement SVGR as closely as possible:
cat my-file.svg | oxvg jsx --template template.jsx | prettier > my-file.svg.jsxThe piping into Prettier in that example is telling. The output is a component file, not a minified asset, and it is expected to go through a formatter like any other source file.
The crates are separable, and the path one is marked unstable
For Rust developers, the project splits functionality into separate crates that can be used independently, and the readme names the categories: libraries for DOM parsing and traversal, path handling, optimisation and manipulation.
The workspace dependency list in the Cargo manifest shows how fine the split is. There is `oxvg_actions` for the action system, `oxvg_ast` for the DOM-like types, `oxvg_collections` for SVG content types, `oxvg_optimiser` for the plugins, `oxvg_path` for path definitions, `oxvg_jsx`, `oxvg_lint`, `oxvg_diagnostics`, `oxvg_parse` and `oxvg_serialize`.
The AST crate is worth a note because it explains how the tool works. It provides a set of types you can use to implement a DOM similar to that of the browser web standards, and it is not a 1-to-1 match, it is designed for easily traversing and manipulating the DOM. There is currently an implementation suitable for use with either the xml5ever or the roxmltree parser, and it can parse and serialise XML, SVG and HTML documents, implement commonly used browser APIs for DOM nodes, elements and attributes, and provide an implementation of selectors for DOM CSS queries.
So the optimiser is built on a real DOM rather than on a tree walker, which is a reasonable explanation for both the speed and the compatibility work.
The collections crate provides types for SVG content, with parsing attributes into structured data and enumerators for known elements, attributes and namespaces. The path crate is a library for parsing, optimising and serialising path definitions such as a path d attribute, and it carries an explicit warning: please expect some instability as we may add new features to enable simple manipulations for paths in the future.
That warning is scoped to one crate, which is the right way to handle it. A path parser that wants to support path manipulation will grow, and the project is telling you which part of the API will move.
Building from source, and the toolchain it expects
Building it yourself takes a clone, a build and a run, and the documented sequence is short:
git clone [email protected]:noahbald/oxvg.git
cd oxvg
cargo build --profile release --package oxvg --bin oxvg
# UNIX
./target/release/oxvg --help
# Windows
.\target\release\oxvg.exe --helpThe `cargo install oxvg` route is the shortcut, and the readme notes you can install it through cargo with `cargo install oxvg` followed by `oxvg --help`. Homebrew is also a supported route with `brew install oxvg`.
The workspace configuration tells you what the project expects from itself. The Rust edition is 2024, the resolver is version 2, and the lints are strict in a way that says something about the priorities: `missing_docs` is set to warn at the workspace level, and clippy runs with the pedantic group enabled. Several clippy lints are explicitly allowed, and the reasons are given inline: `cast_lossless` and `cast_possible_truncation` because lossy conversions are acceptable, `dbg_macro` because it is only for debugging, `float_cmp` because it is not a priority for SVGO parity, and `must_use_candidate` because it is too noisy.
The float comparison allowance is the tell. Comparing floats exactly is wrong in general and necessary in an optimiser that must decide whether a path segment changed, which is exactly the kind of trade a parity-focused tool makes.
The JavaScript side is lighter. The npm package is marked private with an empty files array and a build script that runs recursively across the workspace, and the dev dependencies are minimal: Biome at a pinned 2.5.7 and the Node types. The formatter and linter for the JavaScript and Rust sources is Biome, configured at the root, with a `typos.toml` for spell checking.
The version number, 0.0.9, appears in the Cargo manifest, in the npm package and in the crate version, so the bindings and the library move together rather than drifting.
Where oxvg is the wrong tool
There are three situations where adopting oxvg costs more than it saves, and the first is the most likely one for a team reading this.
The first is an existing SVGO setup that works. The readme says the optimiser aims for SVGO compatibility but is not a 1-for-1 replacement, that some plugins may behave differently, and that there is a parity guide for migrating. If your configuration is tuned, or your build depends on a specific plugin's exact output, the migration is a project with a test suite attached, and the performance win has to be large enough to pay for it.
The second is a project that needs a stable API. At version 0.0.9 the project says what it needs to say about stability, and the path crate in particular asks you to expect some instability as new features are added. For a library you pin in a build, a version series below 1.0 is a signal that the surface will move. The Node addon and the WASM package carry the same version, so the bindings are not insulated from that either.
The third is a job that does not need SVG work at all. The toolchain covers optimisation, linting, transformation and manipulation, and the JSX transformer is a nice touch, but if your pipeline needs to rasterise, to convert between SVG and other vector formats, or to edit vector graphics interactively, none of this helps. For rasterisation the field is settled by resvg, librsvg and the browser's own renderer, and for interactive editing by Inkscape, which the acknowledgements name as an inspiration.
It is also worth being clear about what oxvg is not claiming. The speed claim is qualified as fastest I am aware of, and the 50x figure is specifically about larger file sets. The linter is described as basic. The JSX transformer aims at SVGR compatibility rather than reaching it. None of that is a mark against the project, which is young and says so, but it does tell a reader where the guarantees are thin.
The pattern across the whole project is consistency. It is a rewrite in Rust of a JavaScript toolchain, with SVGO compatibility as the goal, a parity guide for the gaps, a stable core with one explicitly unstable crate, and the same version across the CLI, the bindings and the libraries.
Editorial conclusion
oxvg fits a team that ships a lot of SVG and wants a single fast binary for optimisation, linting and JSX generation, and that is willing to follow a project moving quickly under a 0.0.x version. It is the wrong choice if you have a tuned SVGO configuration and cannot accept behaviour differences, because the readme says it is not a one-for-one replacement and some plugins may behave differently, and it is the wrong choice if you need a stable API, since the version numbering says otherwise. Before adopting, verify three things: how your existing SVGO configuration maps over, using the SVGO parity guide, which crates or packages you actually need, since the CLI, the Node addon, the WASM build and the Rust crates are separate deliverables, and whether the path crate's stated instability affects you, because the documentation says to expect some instability there. The code is MIT licensed, the current version is 0.0.9 from 2026-10-05, and the last push was on 2026-10-16.
Frequently asked questions
What is oxvg and what can it do?
oxvg is an SVG toolchain for optimisation, minification, linting and transformation, written in Rust. It ships an optimiser based on SVGO, a linter with a language server, a scripting action system for manipulating SVG documents, and a JSX transformer, usable as a CLI, through Node, WASM or Rust crates.
How do I install oxvg?
Through cargo with `cargo install oxvg`, through Homebrew with `brew install oxvg`, or from source by cloning the repository and running `cargo build --profile release --package oxvg --bin oxvg`. There are also separate npm packages for the Node addon and the WASM build, and the crates are published for Rust projects.
Is oxvg a drop-in replacement for SVGO?
No. The readme says the optimiser was based on SVGO and aims for compatibility with it, but that it is not a 1-for-1 replacement, so some plugins may behave differently, and it points to an SVGO parity guide for understanding the differences and migrating an existing configuration.
What are oxvg actions and how do they differ from SVGO plugins?
Actions are a set of commands invoked by a program in order to manipulate an SVG document or pull information from it, comparable to Inkscape's actions but without a dependency on the UI or rendering. They are invoked as a command language, for example `oxvg action -- -select path -path-intersect`.
Does oxvg have a linter, and can it run in an editor?
Yes. It includes a basic linter similar to svglint or vnu that can report SVG issues directly from the command line or through its language-server integration, with `oxvg lint serve` starting the server and `oxvg lint check w3c/ -r` reporting diagnostics to stderr.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/noahbald-oxvg)