percy is a free, open source browsers & extensions project written in Rust and released under Apache-2.0. It has 2,315 GitHub stars, 84 forks and 44 open issues, and was last pushed 25 days ago. On this registry it ranks #98 of 136 tracked projects in Browsers & Extensions, with 5 head-to-head comparisons available.

What is percy?

Percy is a Rust library and build workflow for creating frontend browser applications that compile to WebAssembly, with support for server side rendering, aimed at Rust developers who want to write client side, server side, or isomorphic web apps without leaving Rust.

What it is

Percy lives in the Rust and WebAssembly ecosystem. It provides the percy-dom crate, a virtual DOM implementation, together with an html! macro for writing view markup, and it builds on wasm-bindgen, js-sys, and web-sys to talk to browser APIs. Applications are compiled with cargo build --target wasm32-unknown-unknown and then run through wasm-bindgen with --target web and --no-typescript to produce JavaScript glue and a .wasm binary that a static file server can host. Percy supports three shapes of application: client side rendering only, server side rendering only, or both at once, which the project calls an isomorphic web app.

The concrete problem it solves is the split between a Rust backend and a JavaScript frontend. Instead of maintaining two languages, two view layers, and a hand-written bridge between them, Percy lets the same Rust code own the view. It replaces the piecemeal arrangement of a JavaScript framework plus a separate Rust service for teams that already write Rust. Virtual node construction is available through the html! macro or, without a macro, through the virtual-node crate and VirtualNode::new_element. Mounting and patching are handled by PercyDom::new_append_to_mount and pdom.update(end_view).

Key capabilities

  • html! macro for view markup, with Rust comments inside the markup and value interpolation using braces, such as { greetings }.
  • Virtual DOM diffing and patching through PercyDom, including PercyDom::new_append_to_mount and pdom.update(end_view).
  • Virtual nodes without a macro via the virtual-node crate and VirtualNode::new_element.
  • Client side rendering, server side rendering, and isomorphic rendering, demonstrated by the examples/isomorphic example.
  • percy-dom crate version 0.11, used alongside wasm-bindgen = "0.2", js-sys = "0.3", and web-sys = "0.3", with crate-type = ["cdylib"] in Cargo.toml.
  • Compilation to wasm32-unknown-unknown and JavaScript binding generation with wasm-bindgen-cli using --target web --no-typescript --out-dir ./public.
  • Browser API access through web-sys feature flags such as Document, MouseEvent, Window, and console.

Who uses it and how

  • Rust developers building a single-page browser app who want the view layer written in Rust rather than JavaScript, following the cargo new client-side-web-app --lib quickstart.
  • Teams shipping isomorphic applications that render the same views on the server and in the browser, using the examples/isomorphic example as a starting point.
  • Developers serving the compiled output from a static file server that sends the application/wasm MIME type for the .wasm binary.
  • Newcomers following The Percy Book, which the README names as the full walkthrough beyond the light introduction.
  • Projects already tracking Percy on GitHub, where it has 2,315 stars and 84 forks, with 44 open issues and a last push dated 2026-08-25.

Getting started

Start with cargo new client-side-web-app --lib, add percy-dom = "0.11" and the wasm-bindgen dependencies to Cargo.toml, then cargo install wasm-bindgen-cli and run the build.sh script that compiles for wasm32-unknown-unknown and copies index.html and app.css into public/. Serve that directory with any static file server that supports the application/wasm MIME type, such as the example's http ./public --port 8080.

How it compares

No list of paid products that Percy replaces is provided in the facts, and no comparable tools are named there either. On the record available here, Percy stands alone in this registry.

When to use it — and when not to

A self-hoster must operate a full Rust toolchain, install wasm-bindgen-cli, keep a build.sh step that targets wasm32-unknown-unknown, and serve the output from a static server configured for the application/wasm MIME type. Developers who do not already work in Rust, or who want a batteries-included framework with a large component ecosystem, should not pick it. The README is deliberately a light introduction and defers the real walkthrough to The Percy Book, and on stable Rust text nodes must be wrapped in quotation marks until span locations are stabilized in the compiler, which is a sharp edge for anyone coming from nightly.

project readme (upstream, from github) — read inline

Percy

Actions Status Actions Status

Build frontend browser apps with Rust + WebAssembly. Supports server side rendering.

The Percy Book

This README gives a light introduction to Percy. Check out The Percy Book for a full walk through.

Stable Rust

Percy compiles on stable Rust with one caveat:

On nightly Rust you can create text nodes without quotes.

// Nightly Rust does not require quotes around text nodes.
html! { <div>My text nodes here </div> };

On stable Rust, quotation marks are required.

// Stable Rust requires quotes around text nodes.
html! { <div>{ "My text nodes here " }</div> };

This difference will go away once span locations are stabilized in the Rust compiler - Rust tracking issue.

Getting Started

The best way to get up to speed is by checking out The Percy Book, but here is a very basic example to get your feet wet with.

Quickstart - Getting your feet wet

Percy allows you to create applications that only have server side rendering, only client side rendering, or both server and client side rendering.

Here's a quick-and-easy working example of client side rendering that you can try right now:


First, Create a new project using

cargo new client-side-web-app --lib
cd client-side-web-app

Add the following files to your project.

touch build.sh
touch index.html
touch app.css

Here's the directory structure:

.
├── Cargo.toml
├── build.sh
├── index.html
├── app.css
└── src
    └── lib.rs

Now edit each file with the following contents:

# contents of build.sh

#!/bin/bash

cd "$(dirname "$0")"

mkdir -p public

cargo build --target wasm32-unknown-unknown
wasm-bindgen target/wasm32-unknown-unknown/debug/client_side_web_app.wasm --no-typescript --target web --out-dir ./public --debug
cp index.html public/
cp app.css public/

// contents of src/lib.rs

use wasm_bindgen::prelude::*;
use web_sys;

use percy_dom::prelude::*;

#[wasm_bindgen]
struct App {
  pdom: PercyDom
}

#[wasm_bindgen]
impl App {
    #[wasm_bindgen(constructor)]
    pub fn new () -> App {
        let start_view = html! { <div> Hello </div> };

        let window = web_sys::window().unwrap();
        let document = window.document().unwrap();
        let body = document.body().unwrap();

        let mut pdom = PercyDom::new_append_to_mount(start_view, &body);

        let greetings = "Hello, World!";
        
        // You can also use the `virtual-node` crate to create virtual nodes without a macro.
        let some_span = VirtualNode::new_element("span");

        let end_view = html! {
           // Use regular Rust comments within your html
           <div class=["big", "blue"]>
              /* Interpolate values using braces */
              <strong>{ greetings }</strong>
            
              {span}

              <button
                class="giant-button"
                onclick=|_event| {
                   web_sys::console::log_1(&"Button Clicked!".into());
                }
              >
                // No need to wrap text in quotation marks (:
                Click me and check your console
              </button>
           </div>
        };

        pdom.update(end_view);

        App { pdom }
    }
}

# contents of Cargo.toml

[package]
name = "client-side-web-app"
version = "0.1.0"
authors = ["Friends of Percy"]
edition = "2018"

[lib]
crate-type = ["cdylib"] # Don't forget this!

[dependencies]
wasm-bindgen = "0.2"
js-sys = "0.3"
percy-dom = "0.11"

[dependencies.web-sys]
version = "0.3"
features = [
    "Document",
    "MouseEvent",
    "Window",
    "console"
]

<!-- contents of index.html -->
<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <link rel="stylesheet" type="text/css" href="app.css"/>
        <title>Client Side Demo</title>
    </head>
    <body style='margin: 0; padding: 0; width: 100%; height: 100%;'>
        <script type="module">
            import init, {App} from '/client_side_web_app.js'
        
            async function run ()  {
                await init('/client_side_web_app_bg.wasm')
                new App()
            }
        
            run()
        </script>
    </body>
</html>

/* contents of app.css */
.big {
  font-size: 30px;
}
.blue {
  color: blue;
}
.giant-button {
  font-size: 24px;
  font-weight: bold;
}

Now run

# Used to compile your Rust code to WebAssembly
cargo install wasm-bindgen-cli

# Or any other static file server that supports the application/wasm mime type
cargo install https

chmod +x ./build.sh
./build.sh

# Visit localhost:8080 in your browser
http ./public --port 8080

And you should see the following:

Client side example

Nice work!

More Examples

API Documentation

Contributing

Always feel very free to open issues and PRs with any questions / thoughts that you have!

Even if it feels basic or simple - if there's a question on your mind that you can't quickly answer yourself then that's a failure in the documentation.

Much more information on how to contribute to the codebase can be found in the contributing section of The Percy Book!

To Test

To run all of the unit, integration and browser tests, grab the dependencies then :

./test.sh

License

MIT

Frequently asked questions

Is percy free to use?

percy is open source under the Apache-2.0 licence. There is no licence fee and no seat count — you can self-host it or, where the project offers one, pay a vendor for a managed version instead.

What does percy do?

Build frontend browser apps with Rust + WebAssembly. Supports server side rendering.

What is percy written in?

percy is primarily written in Rust. Its source is publicly available at https://github.com/chinedufn/percy, and it has 2,315 GitHub stars.