# resvg: a small Rust SVG renderer that leaves out everything dynamic

> resvg renders the static subset of SVG to raster images in pure Rust, with no system libraries and identical output on every platform. It ships as a Rust library, a C library and a CLI, and it refuses animations and scripting on purpose.

**linebender/resvg** — An SVG rendering library.

- Repository: https://github.com/linebender/resvg
- Stars: 4,112 · Forks: 355
- Language: Rust
- License: Apache-2.0
- Published: 2026-10-08 · Updated: 2026-10-08 · Language: en
- Canonical page: https://hysenlabs.com/projects/linebender-resvg

## Why a browser is not a rendering dependency

The argument the README opens with is about scope. SVG 1.1 is close to nine hundred pages of specification, and a complete implementation effectively means a browser engine, which is a heavy thing to link into a server or ship inside a WASM module. The resvg project accepts the opposite trade: render the static subset well, and leave out everything that needs a program running next to the picture.

That decision shows up as a hard boundary rather than a list of missing extras. The project targets the static SVG subset and explicitly does not support the `a`, `script`, `view` or `cursor` elements, and it does not handle events or animations. There are no plans to add animations, and SVG Tiny 1.2 is neither supported nor planned. SVG 2 work is tracked separately under an `svg2` issue label and in `docs/svg2-changelog.md`.

For a thumbnailer, an icon build step, a PDF pipeline or a static site generator, that boundary is exactly where the interesting work used to start and end. The hard part of rendering SVG has always been the messy corners of the specification, not the animation loop, and resvg spends its effort there.

## Two crates: usvg parses, resvg paints

Parsing and rendering are separate steps in resvg, and they live in separate libraries. The `usvg` crate turns SVG and CSS into a simplified tree, and the `resvg` crate walks that tree and paints it with tiny-skia. The README is explicit that this lets you write your own renderer on top of usvg using any 2D library you like, which is a genuinely useful shape if you already have a rasterizer and only want correct SVG parsing and font handling.

The workspace file confirms how the pieces are laid out. The default member is the `resvg` crate itself, so a plain `cargo` invocation in the repository root builds the renderer rather than the whole set:

```toml
[workspace]
members = [
    "crates/c-api",
    "crates/resvg",
    "crates/usvg",
    "crates/usvg/codegen",
]
default-members = ["crates/resvg"]
```

There is also a `c-api` crate, which is what makes the C library claim in the README possible, and a `codegen` crate under `crates/usvg`. A fifth member, the Windows Explorer thumbnailer in `tools/explorer-thumbnailer`, is commented out of the workspace. The release notes for v0.48.1 still describe `resvg-explorer-extension.exe` as an SVG thumbnailer for Windows Explorer, so the tool is shipped while it sits outside the default build.

Underneath, the parsing and text work is delegated to roxmltree for XML, simplecss for CSS, rustybuzz for shaping, ttf-parser for font parsing, fontdb for font databases and pico-args for command line parsing. Rendering goes through tiny-skia.

## Adding it to a Rust project

The README does not spell out a command for pulling resvg into a project, and the installation detail lives on the published crate page and on docs.rs instead. Both linked from the README. For a Rust consumer the dependency is the `resvg` crate, and `usvg` comes in when you want the tree rather than the pixels.

```bash
cargo add resvg
```

The README carries a Rust 1.85.0 minimum in its build badge, so that is the toolchain floor the project advertises. If you also want the C library or the Windows thumbnailer, those are built from the workspace rather than pulled from crates.io.

There is a production profile in the workspace file, and its settings are worth knowing about if you plan to ship the binary:

```toml
[profile.production]
inherits = "release"
opt-level = 3
debug = false
lto = true
codegen-units = 1
strip = true
```

Link time optimization, a single codegen unit and symbol stripping all point the same way. The README states the resulting CLI is under 5MB and needs no external dependencies, so the artifact you copy onto a build machine is the whole program.

## What the 1,600-test suite does and does not cover

Correctness is the argument for the whole project, so it is worth being precise about what the tests establish. The README says the suite contains around 1,600 tests and that those are only SVG to PNG regression tests, excluding tests inside dependencies. It is also published separately from resvg, which the README frames as a deliberate choice so that anyone building a different SVG library can test against the same data.

That suite also produces the numbers behind the two charts at the top of the README, and a support table hosted outside the repository. The README is blunt about how it treats competitors: several libraries are excluded because they do not clear a 25 percent pass rate, naming wxSvg, LunaSVG and nanosvg. That is a judgement by the project about its own test data, and it is fair to read the table as one library's measurement of others rather than a neutral benchmark.

The honest summary is that resvg has an unusually public correctness story for a graphics library, and that the story is scoped to static rendering. Anything about text layout fidelity on a specific platform is not settled by these tests, because the answer depends on the fonts you hand the library.

## Reproducible pixels, and the price of that promise

Because resvg does not link against system libraries, the README claims identical output across supported platforms, down to individual pixel values, so a file rendered on x86 Windows matches one rendered on ARM macOS. That is a real engineering benefit for anyone who caches derived images, compares screenshots in review, or needs a build artifact that does not change when the machine does.

The price is the absence of native text rendering. The README states it plainly: no system libraries means no platform text stack, and it argues native text rendering is tuned for small horizontal text, which is not the common case in SVG. Font memory mapping is also called out as inherently `unsafe`, though the README notes there is almost no `unsafe` code in the project as a whole. Beyond memory safety, the project says it has extensive checks against endless loops and stack overflow through recursion, which matters when the input is a file someone uploaded.

Portability has rough edges too. The README says there are some with obscure CPU architectures and mobile operating systems, mainly around loading system fonts. Those are the places where the reproducibility claim and the platform integration claim meet, and it is where you should expect to do your own work rather than rely on defaults.

## Versioning and licensing, and when to reach for something else

resvg is pre-1.0 and moving: v0.48.0 and v0.48.1 both landed on 2026-08-02, after v0.47.0 on 2026-02-10, and the last push was on 2026-09-16. A version line that ships twice in one day and sits below 1.0 is a moving target for anything that pins a dependency, so the upgrade path is part of the evaluation rather than an afterthought.

Licensing is worth a close read because two surfaces disagree in a benign way. The repository's license field reports Apache-2.0, while the README offers either the Apache License, Version 2.0 or the MIT license at your option, and the workspace file records `Apache-2.0 OR MIT`. Both `LICENSE-APACHE` and `LICENSE-MIT` sit at the top of the tree. If you need MIT compatibility, the README and the workspace metadata both support it, so pick MIT explicitly rather than assuming from the repository header.

The alternatives split along a different line. librsvg and the browser engines try to cover the whole specification and pay for it in size and platform dependencies. resvg gives up the dynamic parts and keeps the static rendering honest, with a public test suite you can check your own implementation against. Choose it when you control the input files and need the same bytes everywhere. Leave it when the SVG comes from arbitrary users or from a design tool that relies on animation.

## Conclusion

resvg is the right tool when a server, a build step or a WASM module has to turn an SVG you control into pixels, and the file contains no scripting, no animation and no external links. The split between usvg and resvg means you can also keep the parsed tree and draw it with a different rasterizer, which is the more interesting option for anyone with an existing drawing stack. It is the wrong tool for arbitrary user-submitted SVG, for anything that needs text hinted by the platform, and for a production dependency that wants a stable API, since the project is still on a 0.x version line. Start by rendering one of your own files with the CLI and comparing the output against your current pipeline; if the two differ, the difference is usually fonts, and that is where the real evaluation work sits.

## FAQ

### Is resvg still actively developed?

The repository is not archived and the last push was on 2026-09-16, with v0.48.1 published on 2026-08-02 after v0.47.0 in February 2026. The project is on a 0.x version line, so expect version churn rather than a stable API promise.

### Does resvg render SVG animations?

No, and there are no plans to add them. resvg targets the static SVG subset, so it leaves out the `a`, `script`, `view` and `cursor` elements along with events and animations. SVG Tiny 1.2 is also out of scope permanently.

### Can I use resvg as a C library or from JavaScript?

The README lists a Rust library, a C library and a CLI application as the three interfaces. The workspace includes a `crates/c-api` member for the C side, and the README says the library is guaranteed to work anywhere Rust compiles, including WASM.

### Which license applies to resvg?

The README offers either the Apache License, Version 2.0 or the MIT license at your option, and the workspace records `Apache-2.0 OR MIT`. The repository's license field shows Apache-2.0 on its own, and both license files are present in the tree.

## Sources

- [Issues](https://github.com/linebender/resvg/issues)
- [License: Apache-2.0](https://github.com/linebender/resvg/blob/main/LICENSE)
- [linebender/resvg on GitHub](https://github.com/linebender/resvg)
- [README](https://github.com/linebender/resvg/blob/main/README.md)
- [Releases](https://github.com/linebender/resvg/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/linebender-resvg
