# rari: a React Server Components framework with a Rust runtime underneath

> rari is an MIT-licensed TypeScript project that puts a Rust HTTP server, RSC renderer and router with embedded V8 under a Next.js-shaped React framework, bundled with a Rolldown-powered Vite toolchain. The judgement is that the architecture is the interesting part, and that the published benchmark numbers are the project's own and come from a separate harness at an older version.

**rari-build/rari** — rari: High-performance React Server Components framework powered by a Rust runtime, delivering 14.5x faster response times (0.12ms vs 1.74ms) and 53.1x higher throughput (89,371 vs 1,683 req/sec) than Next.js with zero-config setup.

- Repository: https://github.com/rari-build/rari
- Website: https://rari.build
- Stars: 1,180 · Forks: 34
- Language: TypeScript
- License: MIT
- Published: 2026-10-19 · Updated: 2026-10-19 · Language: en
- Canonical page: https://hysenlabs.com/projects/rari-build-rari

## Three layers, and the middle one is the point

rari is a React Server Components framework running on a Rust runtime, and the README describes it as three layers.

The first is a Rust runtime: an HTTP server, an RSC renderer, and a router with embedded V8. The second is a React framework: an app router, server actions, and streaming with Suspense. The third is a build toolchain: Rolldown-powered Vite bundling and TypeScript 7 type checking.

The summary sentence is the one to hold on to: you write standard React, and the runtime underneath is Rust instead of Node.

That is a different bet from most React frameworks. Next.js runs the server components on Node, and the cost of that decision is the well-known one: a JavaScript runtime doing the rendering work, with a V8 instance per process. rari's bet is that the rendering path is hot enough to justify moving the HTTP server, the RSC renderer and the router into Rust, while keeping V8 embedded for the JavaScript that React itself needs.

The repository layout backs up the three-layer claim. There is a `crates/` directory for the Rust workspace, a `packages/` directory for the JavaScript side, a `web/` directory for the documentation site, `examples/` with a `playground/`, `tools/` for workspace members that are not crates, and `test/` for the test suites. The `Cargo.toml` workspace members are `crates/*` and `tools/*`, with `tools/bundle-react-esm` excluded, and the workspace edition is 2024.

The Rust side is a serious dependency set rather than a thin wrapper. It includes `tokio` for the async runtime, `clap` with derive for the CLI, `serde` and `serde_json`, `sha2`, `regex`, `thiserror` and `tracing` for error handling and observability, and `uuid` with the v4 feature.

There is also a Deno ecosystem alignment, and it is worth noting because it is unusual. The Cargo manifest pins a long list of `deno_*` crates to exact versions, with a comment saying they are Deno ecosystem aligned exact pins to be bumped as a coordinated set with Deno releases. So the JavaScript engine underneath is not a hand-rolled engine but a Deno-derived core, embedded in the Rust runtime.

## The app router is deliberately a Next.js clone

The React layer is the part most teams will interact with, and the design decision is that it should feel familiar.

The App Router gives file-based routing with layouts, loading states and error boundaries. Server-Side Rendering produces pre-rendered HTML with instant hydration. React Server Components are server components by default, with client components when you need them. There are Server Actions for data mutations, and streaming SSR with progressive rendering and Suspense boundaries, plus automatic loading skeletons during navigation.

The resemblance to Next.js is not accidental, and the README does not pretend otherwise. The feature list reads like a Next.js feature list, the terminology is the same, and the benchmark section compares against Next.js directly. The intent is that a team can move an existing app router project over without rewriting its routing conventions.

Two details are worth calling out. The framework advertises node_modules support, described as standard npm package resolution without an `npm:` specifier, which is a compatibility detail that matters if you are importing from the ecosystem rather than from a bundled copy. And the project is TypeScript-first, with full type safety across the server and client boundary, which is the practical argument for the embedded V8: the type checking runs across the boundary rather than stopping at it.

The `examples/playground/` directory is the one example in the repository, and it is the fastest way to see what a rari app looks like without reading the documentation.

## Zero-config setup rests on prebuilt binaries

The quick start is three commands, and the claim is that there is nothing to configure.

```bash
npm create rari-app@latest my-app
cd my-app
npm run dev
```

After that your app runs at `http://localhost:5173`, and the port is the Vite default, which tells you that the dev server is the standard Vite dev server rather than something bespoke.

The zero-config claim rests on pre-built binaries. The feature list says it works out of the box with pre-built binaries, and that is what makes the first command enough. There is no Rust toolchain to install and no runtime to compile for a first run, which is a real difference from most Rust-backed web frameworks.

The trade is that the prebuilt binary is a snapshot of the runtime, and a team that needs to patch the runtime itself is back to building from source. The repository supports that path, and the `justfile` shows what it involves.

The justfile is a `just` command runner with a Windows shell setting and a bash default, and the setup recipe is the interesting one. It runs a prerequisite check, then installs `cargo-binstall` with `cargo install`, and then uses `cargo binstall` to install `cargo-insta`, `cargo-nextest` and `cargo-machete` in one step each. The Node side enables corepack and runs `pnpm install`. The prerequisite check itself is a script that exits with a message telling you to install Rust from rustup.rs, Node.js from nodejs.org, or to run `corepack enable` for pnpm.

The build recipe is a four-stage pipeline: `bundle-react-esm build-snapshot build-rust build-node`. The snapshot stage is the interesting one, because the V8 startup snapshot has to exist before the runtime can be built. The recipe checks for `crates/rari/snapshots/RARI_SNAPSHOT.bin`, and rebuilds it if the file is missing, empty, or older than `Cargo.toml` or the extension sources under `crates/rari/src/runtime/ext`. So a stale snapshot triggers a rebuild rather than a silent misbehaviour.

The `web/` directory holds the documentation, and `rari.build/docs` is where the guides live.

## The benchmark numbers are the project's own, at an older version

The performance section is the most eye-catching part of the README and also the part that needs the most careful reading.

The repository description claims 14.5 times faster response times, 0.12ms against 1.74ms, and 53.1 times higher throughput, 89,371 against 1,683 requests per second, than Next.js with zero-config setup. The README carries the tables, and the note above them says the benchmarks were last updated on August 10, 2026, at rari v0.15.9.

That version number matters. The current release is v0.17.5, published on 2026-10-15, so the measurements predate the code you would install by two minor versions.

The response time table gives an average of 0.12ms against 1.74ms, a P95 of 0.12ms against 2.44ms, and a bundle size of 287 KB against 573 KB, described as 50 percent smaller. The throughput table, under 50 concurrent connections over 30 seconds, gives 89,371 requests per second against 1,683, an average latency of 0.56ms against 29.73ms, a P95 latency of 0.90ms against 36.70ms, and zero errors on both sides. The build table gives 1.12s against 3.88s for build time.

The streaming table is the most interesting because it is where the numbers are close. Time to first byte is 1ms against 12ms, but first content is 107ms against 108ms, last byte is 1007ms against 1009ms, resolved cards are 10 out of 10 on both sides, and throughput is 24.99 per second on both. The README explains that last-byte time is dominated by intentional roughly 1000ms card delays rather than framework overhead, and the fact that the project prints that caveat next to the table is a good sign about how the numbers are meant to be read.

The benchmarks are reproducible and the methodology is in a separate repository, `rari-build/benchmarks`, with the README linking it. There is also a CodSpeed badge in the header, which points at continuous performance tracking on the repository's own code rather than on the comparison.

What the tables do not establish is that a real application will see these gains. A 0.12ms response time suggests the benchmark is measuring a minimal route, and a 50 percent bundle reduction is the kind of number that depends entirely on what the application contains.

## A monorepo with a Rust and TypeScript toolchain side by side

The engineering surface of the project is worth understanding, because it is where the real cost of this architecture lives.

The JavaScript side is a pnpm workspace with `pnpm@12.9.1` as the declared package manager, and the root package is `@rari/monorepo`, private, with scripts that fan out across the workspace using `pnpm -r run build`, `pnpm -r run typecheck` and `pnpm -r run clean`. The formatting is done by `vite-plus`, invoked as `vp fmt` and `vp fmt --check`, and the same tool provides the unit test runner, `vp test`, with a coverage variant. End-to-end tests are Playwright, with `playwright test` plus a UI mode and a smoke spec.

Linting is a long composed command that runs the format check, the per-package lints, `vp lint` over the Rust, test and example directories, and `eslint` across the crates, packages, web, examples, test and tools directories. There is also `lint:knip` for unused dependency and export detection, which is the kind of check that keeps a monorepo from accumulating dead weight.

The Rust side has its own linting, a `rustfmt.toml`, a `rust-toolchain.toml` pinning the compiler, and a `clippy` configuration in `.cargo/`.

A `knip.jsonc` file at the root and a `cliff.toml` for changelog generation round out the tooling, along with `railpack.json` and `railway.toml` for deployment.

The split between the two ecosystems is where a contributor's time goes. A change to the RSC renderer is a Rust change with a snapshot rebuild; a change to the app router is a TypeScript change with a Vite build. The `justfile` and the `just --list -u` default recipe exist so that both sets of commands are discoverable in one place, and that is a small but real kindness to anyone joining the project.

The `packages/` directory holds the JavaScript packages, and the npm package is `rari` itself, published alongside the `use-cache-binaries` package at the same version.

## Conclusion

rari fits a React team that wants to write ordinary React with server components, server actions and an app router, and that is willing to run a non-Node runtime and to accept a young toolchain in exchange for it. It does not fit a team that needs a proven production track record, and it does not fit anyone who needs to run on a platform where the prebuilt binaries are not offered. Verify first that the version you install matches the documentation you are reading, since the published benchmarks were taken at v0.15.9 in August 2026 while the current release is v0.17.5, that the Rust toolchain version pinned in `rust-toolchain.toml` matches yours, and that the app router and server action semantics in the documentation at rari.build/docs are the ones you need, because the framework deliberately mirrors Next.js conventions rather than inventing its own.

## FAQ

### How do I create a new rari application?

Run `npm create rari-app@latest my-app`, change into the directory and run `npm run dev`. The app is then served at `http://localhost:5173`. The zero-config claim rests on the project shipping pre-built binaries, so no Rust toolchain is needed for a first run.

### What are the three layers of the rari framework?

A Rust runtime with an HTTP server, an RSC renderer and a router with embedded V8; a React framework with an app router, server actions and streaming with Suspense; and a build toolchain with Rolldown-powered Vite bundling and TypeScript 7 type checking. The embedded JavaScript engine is Deno-derived, with the deno_* crates pinned as an aligned set.

### How does rari compare with Next.js on performance?

The project's own benchmarks, last updated on August 10, 2026 at rari v0.15.9, report an average response time of 0.12ms against Next.js at 1.74ms, and 89,371 requests per second against 1,683 under 50 concurrent connections. The methodology is published in the separate rari-build/benchmarks repository, and the current release is v0.17.5.

### Do I need Rust installed to work on rari?

Not to run an app, because pre-built binaries are used. To build from source you need Rust, Node.js and pnpm, and the repository's `just setup` recipe installs the Rust tooling with cargo-binstall, enables corepack for pnpm and runs the install. The build also requires a V8 startup snapshot, which the justfile regenerates when missing or stale.

### Is rari licensed permissively?

Yes, MIT, with the licence file at the repository root and the Cargo workspace also declaring `license = "MIT"`. The project also has commercial sponsors listed in the README, including Namespace for cloud infrastructure and Neon for serverless Postgres.

## Sources

- [License: MIT](https://github.com/rari-build/rari/blob/main/LICENSE)
- [Project website](https://rari.build)
- [rari-build/rari on GitHub](https://github.com/rari-build/rari)
- [README](https://github.com/rari-build/rari/blob/main/README.md)
- [Releases](https://github.com/rari-build/rari/releases)

---

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