Framework
LukeMathWalker/pavex avatar
LukeMathWalker/pavex

Pavex asks you to sign up for a beta, not to add a crate

A backend framework for Rust professionals

2,069 stars79 forksRustApache-2.0

At a glance

What is it?
Pavex is a Rust backend framework built as a compile-time code generator plus a set of runtime crates. Getting it starts with a beta signup rather than a dependency line, and one of its workspace crates trails the rest by three patch releases.
Who is it for?
Pavex fits a team that wants a Rails-shaped workflow in Rust and is willing to absorb a code generator with its own build step and its own diagnostic surface. It does not fit a team that needs a settled public API today, because access runs through a beta signup page rather than a documented dependency line.
Can I use it commercially?
Yes. Apache-2.0 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 161 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 6, 2026, and from our analysis. They are not legal advice.

Editorial analysis

Pavex splits a backend framework into a compiler and a runtime

Most Rust web frameworks are libraries you call at runtime. Pavex takes the opposite shape: the workspace is split into a compiler/ tree and a runtime/ tree, and the compiler side is a set of crates whose names carry the CLI. pavexc is the driver, with pavexc_attr_parser, pavexc_cli_client, pavexc_cli_deps, pavexc_cli_diagnostic, pavexc_cli_flock and pavexc_cli_shell sitting beside it. Two more compiler crates, pavex_bp_schema and generate_from_path, along with persist_if_changed and a pavex_test_runner, make it plain that the framework writes files on your disk before your program ever runs. The runtime side is where your handlers live, and pavex_macros, pavex_miette, pavex_tracing and the pavex_session family are its parts. The README asks for the productivity of Ruby on Rails, Spring or ASP.NET Core at the speed of handwritten code with the abstractions removed, and that compiler/runtime split is how the project intends to get there: the abstractions exist at build time and largely disappear at run time. ARCHITECTURE.md is the file that explains the mechanism, and the README treats reading it as the next step after the pitch.

The README says closed beta and the workspace publishes versioned crates

The first thing to reconcile is a status line that disagrees with the manifests. The project status section says Pavex is currently in a closed beta, that you sign up for early access, and that project updates are published regularly in a series of posts on the maintainer’s own blog, going back to a vision piece from December 2022. Then Cargo.toml carries a [workspace.package] version, a repository field and a homepage, and the [workspace.dependencies] table pins a dozen path dependencies to explicit version strings rather than leaving them workspace-only. None of that contradicts a beta in a strict sense, since a beta can publish builds. What it does mean is that a pinned version in your lockfile tells you what shape the code had, not that the public surface is settled. The README also never gives a cargo add line, no crate installation command, and no getting-started section, so there is no documented path from a blank project to a running server inside the repository itself.

The workspace metadata that governs all of it is short enough to quote:

toml
[workspace.package]
edition = "2024"
repository = "https://github.com/LukeMathWalker/pavex"
homepage = "https://pavex.dev"
license = "Apache-2.0"
version = "0.2.10"

Access starts at pavex.dev, not at the crate registry

This is the practical constraint on evaluating Pavex, and it is stated plainly rather than hidden. The README sends you to https://pavex.dev/docs/ for a thorough introduction and its design philosophy, and the project status section sends you to https://pavex.dev to sign up for early access. That signup is the entry point to the framework itself, and the repository contains no installation command to copy. So the honest tutorial is short: read ARCHITECTURE.md to understand the build-time model, read CONTRIBUTING.md if you plan to work on the code, and get access through the signup page before you plan an evaluation. The contributing section is unusually concrete about the cost of a patch, and it sets a line count as the threshold: a typo or a small bug fix with a regression test can go straight to a pull request, while anything beyond 20 lines of code needs an issue opened first. That number tells you how the maintainer thinks about incoming changes, and it is worth reading before you prepare a patch.

One workspace crate is pinned two versions behind the rest

The [workspace.dependencies] table is worth reading line by line, because it is where the drift shows. Nearly every entry carries the same version string as the workspace package: pavex, pavex_macros, pavex_miette, pavex_tracing, pavexc, the three CLI helpers, pavexc_attr_parser, pavexc_cli_client and the session crates all match. One does not. pavex_test_runner is declared at 0.2.7 while the rest of the family sits at 0.2.10, a gap of three patch releases on the component that runs your tests. Whether that is deliberate pinning or a forgotten update is not something the repository states. It matters practically, because a test runner is exactly the crate where you would want current behavior and where a stale interface would surface as confusing test output. The workspace also sets resolver = "3" and edition = "2024" in [workspace.package], and a rust-toolchain.toml sits at the repository root, so the toolchain expectation is pinned by file rather than left to whatever cargo finds on the machine.

Sessions are four separate crates, not one switch

Look at the runtime/sessions/ subtree and you find a different design decision from the one most frameworks make. Instead of a single session abstraction with a pluggable backend chosen at runtime, Pavex ships pavex_session as the core, then pavex_session_sqlx, pavex_session_redis and pavex_session_memory_store as separate crates. Each one carries its own path and version pair in the workspace table, which means the storage choice is a compile-time dependency decision rather than a configuration key. That fits the project's stated philosophy of erasing abstractions at build time, and it also means swapping a memory store for Redis is a Cargo.toml change plus an import change, not a settings edit. The same build-time approach runs through pavex_tracing and through pavex_miette, which is the crate behind the diagnostic rendering on the compiler side. Naming a separate crate for error reporting, when the maintainer has published a post titled Rust web frameworks have subpar error reporting, tells you where the framework intends to compete and what it considers a defect in its peers.

The docs are built by a Python toolchain inside the Rust workspace

A detail worth flagging for anyone cloning the repository: the documentation build is not a Rust build. pyproject.toml at the root defines a project named pavex, and its dependencies are the MkDocs toolchain: mkdocs-material, mike, mkdocs-awesome-pages-plugin, mkdocs-redirects, pymdown-extensions, pygments-ansi-color and md_slash, with pip pulled in as well. requires-python is >=3.13. mkdocs.yml at the root is the config that ties it together, dprint.json handles formatting, and a uv.lock sits next to the Python manifest, with tool.uv.workspace pointing at docs/tools/md_slash. So the repository has two toolchains and two lockfiles, a Cargo.lock for the crates and a uv.lock for the docs tooling. If you contribute a documentation change, you need Python 3.13 available, which is a separate prerequisite from the pinned Rust toolchain. The entry-points block registers a single markdown extension, trailing_slash = "md_slash:makeExtension", which is a small local plugin living in the docs tools workspace.

The Python side is declared just as explicitly:

toml
[project]
name = "pavex"
version = "0.1.0"
requires-python = ">=3.13"
dependencies = [
    "mike>=2.1.3",
    "mkdocs-awesome-pages-plugin>=2.10.1",
    "mkdocs-material>=9.6.23",
]

Note the version mismatch between the two manifests: the crates live at 0.2.10 while the docs project declares 0.1.0 and versions nothing independently of them.

What the compiler writes, and what you write

Two directories outside the crate trees define how the project is used. examples/ holds realworld and starter, plus a reset_starter.sh script whose name tells you the intended workflow: start from the starter, build against it, and reset the directory when you want a clean baseline. That pattern is only coherent if something is being generated into the project directory, which is consistent with persist_if_changed being a crate of its own and with the compiler taking a path through generate_from_path. It also means your project directory is not purely hand-written source, and reviewing it means knowing which parts are yours and which came from the generator. px_workspace_hack/ exists to keep the workspace buildable, and ci.sh at the root is the single entry point for whatever the project's checks are. The compiler uses a file lock, pavexc_cli_flock, which is the sort of detail that only exists in a tool that runs repeatedly during a development loop and has to survive two cargo processes touching the same project at once.

Editorial conclusion

Pavex fits a team that wants a Rails-shaped workflow in Rust and is willing to absorb a code generator with its own build step and its own diagnostic surface. It does not fit a team that needs a settled public API today, because access runs through a beta signup page rather than a documented dependency line. Before adopting, compare the crate versions pinned in the workspace table with each other, read ARCHITECTURE.md, and confirm that your CI can host the Python 3.13 toolchain the docs build expects.

Frequently asked questions

How do I install Pavex for Rust?

The README gives no cargo add command. It points to https://pavex.dev/docs/ for the introduction and to https://pavex.dev for early access signup, because the project is described as being in a closed beta.

How is Pavex different from a runtime-only Rust web framework?

Pavex ships a compiler/ workspace alongside runtime/, with pavexc and its CLI helper crates generating code before the program runs. Compilers and attributes are handled by compiler/pavexc_attr_parser and a builder crate.

Which session storage backends does Pavex support?

The workspace lists pavex_session as the core crate and separate pavex_session_sqlx, pavex_session_redis and pavex_session_memory_store crates. They are chosen as Cargo dependencies rather than through a runtime setting.

What are the contributions rules for Pavex?

The README says a typo fix or a small bug fix with a regression test can go straight to a pull request. Anything beyond 20 lines of code needs an issue opened first, and CONTRIBUTING.md holds the detailed instructions.

Does Pavex need a Rust toolchain and a Python toolchain to build?

Both appear in the repository. Cargo.toml sets edition = "2024" with resolver = "3" and rust-toolchain.toml pins the Rust side, while pyproject.toml requires Python >=3.13 for the MkDocs documentation toolchain.

Official sources

  1. License: Apache-2.0
  2. LukeMathWalker/pavex on GitHub
  3. Project website
  4. README
  5. Releases