Thank you for your interest in contributing to rari! We welcome contributions from the community and are excited to work with you.
rari is a React framework powered by a Rust runtime, designed for performance, scalability, and developer experience. This guide will help you get started with contributing to the project.
Please read and follow our Code of Conduct to ensure a welcoming and inclusive environment for all contributors.
rari is a monorepo that consists of:
- Rust crates (
crates/) - runtime engine and native addons (rari,rari_error,rari_use_cache) - TypeScript/JavaScript packages (
packages/) - framework, CLI, lint, deploy, use-cache, platform binaries - Tests (
test/) - Vitest unit/integration fixtures and Playwright e2e - Examples (
examples/) - sample applications - Web (
web/) - documentation site and landing page - Tools (
tools/) - build, snapshot, release, and binary packaging
Keep Rust and JS names aligned in meaning, but follow each ecosystem’s casing:
| Layer | Convention | Examples |
|---|---|---|
| Rust crates / modules / paths | snake_case |
rari_use_cache, rari_error |
Tools under tools/ |
kebab-case |
tools/prepare-binaries, tools/release |
JS/TS packages / npm names / directories under packages/ |
kebab-case |
@rari/use-cache, create-rari-app, use-cache-darwin-arm64 |
| Paired crate ↔ package | Same words, different separator | crate rari_use_cache ↔ package @rari/use-cache |
When adding a new feature that spans both sides, name the crate with underscores and the published package with dashes. Do not invent a third spelling.
- Node.js
>=24.21.0(seeenginesinpackages/rari/package.json) - Rust nightly via
rust-toolchain.toml(rustup will install it automatically) - pnpm via Corepack (
packageManageris pinned in the rootpackage.json) - just (command runner, optional but recommended)
-
Clone the repository:
git clone https://github.com/rari-build/rari.git cd rari -
Run setup (recommended):
just setup
This will:
- Check prerequisites
- Install Rust tools (cargo-nextest, cargo-machete, cargo-insta)
- Enable Corepack and install pnpm dependencies
Then build once:
just build
Or manually:
corepack enable pnpm install just build # or: pnpm run build after snapshot/binaries are present
-
Verify installation:
just check # Or manually: pnpm run typecheck pnpm run lint
rari/
├── .github/ # Workflows, actions, PR/release templates
├── crates/ # Rust crates
│ ├── rari/ # Main runtime
│ ├── rari_error/ # Shared error types
│ └── rari_use_cache/ # Native 'use cache' transform addon
├── packages/ # JS/TS packages
│ ├── rari/ # Main framework package
│ ├── create-rari-app/ # App scaffolding CLI
│ ├── use-cache/ # '@rari/use-cache' (pairs with rari_use_cache)
│ ├── use-cache-*/ # Platform-specific use-cache natives
│ ├── rari-*/ # Platform-specific rari binaries
│ ├── lint/, deploy/, logger/
├── test/ # Unit, integration, e2e, fixtures
├── examples/ # Example applications
├── tools/ # Build/release helpers
│ ├── prepare-binaries/ # Rust - package native binaries
│ ├── release/ # Rust - release automation
│ ├── snapshot/ # Rust - V8 snapshot generation
│ └── bundle-react-esm/ # JS - vendor React ESM for Flight
├── web/ # Documentation website
├── justfile
├── Cargo.toml # Rust workspace
├── pnpm-workspace.yaml # pnpm workspace + dependency catalogs
└── package.json
just build runs React ESM bundling, V8 snapshot generation, then Rust and Node builds - order matters.
This project uses pnpm workspaces for dependency management. All commands should be run from the root directory unless otherwise specified.
We use just as a command runner to simplify common tasks. Run just to see all available commands.
Using just (recommended):
# Build everything (Rust + Node.js)
just build
# Build only Rust crates
just build-rust
# Build only Node.js packages
just build-node
# Build specific packages
just build-rari
just build-create-rari-app
just build-webOr manually:
# Build all packages and crates (prefer just build - includes snapshot + React ESM)
pnpm run build
# Build only TypeScript packages
pnpm -r run build
# Build only Rust crates (requires a current V8 snapshot under crates/rari/snapshots/)
cargo build --release# Navigate to an example
cd examples/playground
# Install dependencies (if not already done from root)
pnpm install
# Start development server
pnpm run dev# Start the web dev server
just dev
# Or manually:
pnpm --filter @rari/web devTo test your changes:
-
Build the project:
just build # Or: pnpm run build -
Run an example app:
cd examples/playground pnpm run dev -
Test the CLI tool:
cd /tmp pnpm create rari-app test-app cd test-app pnpm run dev
-
Run the rari CLI directly:
just run --help # Or in release mode: just run-release --help
The Rust runtime is located in crates/rari/. Key commands:
Using just (recommended):
# Lint Rust code
just lint-rust
# Fix Rust formatting and linting
just fix-rust
# Run Rust tests with nextest
just test-rust
# Run all Rust tests (including doc tests)
just test-rust-all
# Check for unused dependencies
just machete
# Build release version
just build-rust-releaseOr manually:
# Format Rust code
cargo fmt
# Check for issues
cargo clippy
# Run Rust tests
cargo test
# Build release version
cargo build --releaseTypeScript packages are in packages/ and web/. Key commands:
Using just (recommended):
# Type check all packages
just typecheck
# Lint all packages
just lint-node
# Fix linting issues
just fix-node
# Check for unused dependencies and exports
just knipOr manually:
# Type check all packages
pnpm run typecheck
# Lint all packages
pnpm run lint
# Fix linting issues
pnpm run lint:fix
# Check for unused dependencies
pnpm knipWe use multiple tools to maintain code quality:
- vite-plus (
vp fmt/vp lint) + ESLint + oxlint for JS/TS and shared repo lint - Clippy + rustfmt for Rust
- cargo-machete for unused Rust dependencies
- knip for unused TypeScript dependencies and exports
- Shared JS dependency versions live in pnpm catalogs (
pnpm-workspace.yaml) - prefercatalog:/catalog:<name>over hardcoding versions in package manifests
Run these commands before submitting:
Using just (recommended):
# Lint all code (Rust + Node.js)
just lint
# Fix auto-fixable issues
just fix
# Type check
just typecheck
# Run all checks (lint + test + typecheck)
just check
# Quick development check (faster)
just quick-checkOr manually:
# Lint all code
pnpm run lint
# Fix auto-fixable issues
pnpm run lint:fix
# Type check
pnpm run typecheck- Follow the Rust API Guidelines
- Crate and module names use
snake_case - Use
cargo fmt; runcargo clippyand fix warnings - Add tests for new functionality
- Document public APIs with doc comments
- Deno-related crates are pinned as a set in the workspace
Cargo.toml- bump them together, not via ad-hoccargo updateon a single Deno crate
- Package names and
packages/*directories usekebab-case - Use TypeScript strict mode; prefer type safety over
any - Follow the existing code style (
vp fmt/ ESLint) - Add JSDoc comments for public APIs
- Write tests for new features under
test/ - When a package wraps a Rust crate, keep the npm name the dashed form of the crate name (
rari_use_cache→@rari/use-cache)
Using just (recommended):
# Run all tests (Rust + Node.js)
just test
# Run only Rust tests with nextest
just test-rust
# Run all Rust tests (including doc tests)
just test-rust-all
# Run only Node.js tests
just test-node
# Run specific test by filter
just test-filter "test_name"
# Watch tests (re-run on file changes)
just test-watch
# Run tests with coverage
just test-coverageOr manually:
# Run all tests
pnpm test
# Run Rust tests
cargo test
# Run TypeScript tests
pnpm -r run test- Rust: unit tests inline with
#[cfg(test)], or under cratetests/when integration-style - TypeScript unit/integration: Vitest via
vp test- live undertest/unit/,test/integration/, with helpers intest/helpers/and fixtures intest/fixtures/ - E2E: Playwright under
test/e2e/(pnpm test:e2e/justrecipes that call it) - Prefer colocating coverage with the subsystem you change (e.g. Vite transform bugs →
test/unit/vite/) - Cover edge cases and failure modes, not only the happy path
We follow the Conventional Commits specification:
<type>(<scope>): <description>
[optional body]
[optional footer(s)]
- feat: New features
- fix: Bug fixes
- docs: Documentation changes
- style: Code style changes (formatting, etc.)
- refactor: Code refactoring
- test: Test additions or changes
- chore: Build process or auxiliary tool changes
- perf: Performance improvements
Prefer a concrete subsystem over a vague umbrella:
- rari / rsc / cache - runtime, Flight/Fizz,
'use cache' - vite - Vite plugin / RSC transforms / HMR
- cli -
rariCLI orcreate-rari-app - ci / release / release-notes / dependencies
- docs / examples / web
Use the package or crate name when it helps (use-cache, rari_error), still matching that ecosystem’s casing in prose if you mention paths.
feat(vite): register inline use-server actions for export default
fix(rsc): fail loudly on flight client patch drift
docs: document crate vs package naming
chore(dependencies): bump react vendor pinsReleases are managed by maintainers using our automated release tools:
Using just (recommended):
# Dry run (preview changes)
just release-dry
# Create actual release
just release
# Prepare binaries for release
just prepare-binaries
# Generate changelog
just changelog
# Preview unreleased changes
just changelog-previewOr manually:
# Run release tool
cargo run --release --manifest-path tools/release/Cargo.toml --bin release
# Dry run
cargo run --release --manifest-path tools/release/Cargo.toml --bin release -- --dry-runThe release process:
- Bumps version numbers
- Generates changelog
- Creates git tags
- Publishes to npm
- Uploads binaries to GitHub releases
For minors/majors, add curated notes under .github/release-notes/ before releasing:
cp .github/release-notes/_template.md .github/release-notes/0.15.0.md
# edit Highlights / Breaking Changes, then:
just releaseLookup order: --notes-file / RELEASE_NOTES_FILE → <tag>.md (scoped / → -) → <version>.md.
Manual notes are prepended to the GitHub release body (above the auto-generated commit list) and injected into CHANGELOG.md under the new version heading. Patch releases can skip this and stay cliff-only.
The release tool prepends only the new version section into each package CHANGELOG.md, so older curated Highlights / Breaking Changes are kept. It also passes a package --tag-pattern (e.g. ^rari@) so binary v* tags and other packages are not mixed into the same changelog.
just changelog / just changelog-preview only print unreleased commits to stdout - they do not rewrite CHANGELOG.md.
- Test your changes thoroughly
- Run all quality checks:
just check # Or manually: pnpm run lint pnpm run typecheck pnpm run build - Write descriptive commit messages
- Update documentation if needed
- Add tests for new features
- Small, focused changes are preferred
- Clear description of what the PR does
- Link to relevant issues (if applicable)
- Include screenshots for UI changes
- Update documentation for API changes
- Add changelog entry for user-facing changes
- Automated checks must pass
- Code review by maintainers
- Testing in different environments
- Final approval before merge
- README - Project overview and quick start
- Website - Full documentation and guides
- Examples - Sample applications
- justfile - All available commands
- GitHub Issues - Bug reports and feature requests
- GitHub Discussions - General questions and community discussion
- Discord - Real-time chat with the community
When reporting bugs:
- Check existing issues first
- Use the issue template
- Include reproduction steps
- Provide system information
- Include relevant logs
For new features:
- Search existing issues and discussions
- Describe the use case clearly
- Explain the benefits to users
- Consider implementation complexity
- Be open to feedback and alternatives
The justfile provides convenient commands for all common tasks. Run just or just --list to see all available commands.
Key commands:
just setup- One-time setup for new contributorsjust build- Build everythingjust test- Run all testsjust lint- Lint all codejust fix- Auto-fix linting issuesjust check- Run all checks (CI workflow)just dev- Start web dev server
- Build order matters -
just buildruns React ESM bundling + V8 snapshot before Rust/Node; prefer it over ad-hoc partial builds when unsure - Naming - underscores in Rust, dashes in JS (see Naming conventions)
- Development mode - local tooling often uses
cargo run; published installs use platform binary packages - Cross-platform - CI covers Linux and Windows Namespace runners; test Windows-sensitive paths when you touch them
- Use just - recipes encode dependencies and build order
- Profile before optimizing - Use proper profiling tools
- Benchmark changes - Measure performance impact
- Memory efficiency - Consider memory usage in Rust code
- Bundle size - Keep TypeScript bundles optimized
- Rust debugging - Use
RUST_LOG=debugfor detailed logs - TypeScript debugging - Use browser dev tools and VS Code debugger
- Integration testing - Test the full pipeline from CLI to runtime
Contributors are recognized in:
- README.md - Major contributors
- CHANGELOG.md - Credit for specific changes
- GitHub releases - Acknowledgment in release notes
Thank you for contributing to rari! Your efforts help make rari faster and more accessible for everyone.