An extremely fast R package and project manager, written in Rust.
uvr brings uv-style project management to R: a uvr.toml manifest, a reproducible uvr.lock lockfile, and a per-project isolated library. Packages install from pre-built P3M binaries by default — no compilation, no waiting — with automatic fallback to CRAN source. R versions are managed per-project with no sudo required.
$ uvr init my-analysis
$ uvr add ggplot2 dplyr tidymodels
$ uvr sync # installs from lockfile, idempotent
$ uvr run analysis.RR has several package management tools — renv, pak, rv, rig — each solving a different slice of the problem. After 10+ years of R development, the workflow I kept wanting was the one uv brought to Python: a single tool that handles the full lifecycle, from installing R itself to adding packages to reproducible installs in CI, with no configuration sprawl.
Here is how existing tools compare and where the gaps are:
- renv — the de-facto standard for reproducibility. It snapshots an existing library into a lockfile, but it does not manage R versions ("renv tracks, but doesn't help with, the version of R used") and relies on
install.packages()under the hood, which is slow and requires compilation on Linux. - pak — fast parallel installs and good system dependency detection, but no lockfile and no R version management. A great complement to renv, not a replacement.
- rv — the closest prior art: Rust-based, declarative, fast. It focuses on package resolution. It does not manage R installations, and
rv runis not yet available. - rig — excellent R version manager. No package management or lockfile. Requires admin rights on Windows.
- pixi — conda-based multi-language environment manager. Supports R via conda-forge, but packages come from conda-forge rather than CRAN/Bioconductor/P3M natively. Language-agnostic by design; not R-first.
- rix — Nix-based, with extreme reproducibility including system-level dependencies. Right tool if you need bit-for-bit reproducibility across machines. Requires Nix; a different philosophy than a fast pragmatic workflow.
uvr is the combination of all of the above in one tool, with a single config file (uvr.toml) and a single lockfile (uvr.lock). The design goals are:
- One tool, one config — no juggling renv + rig + pak.
uvr.tomldeclares both the R version and package dependencies. - Lockfile-first —
uvr.lockis the source of truth.uvr syncis always reproducible and idempotent. - Fast by default — P3M pre-built binaries on macOS and Windows; source fallback only when needed.
- R version management built in —
uvr r install,uvr r use,uvr r pinwork the same wayuv pythondoes, because needing a separate tool for this is friction. - CI-native —
uvr sync --frozenis a first-class command, not an afterthought.
If you are happy with renv + rig, that is a perfectly good setup. uvr is for people who want the uv experience in R.
| uvr | renv | pak | rv | rig | pixi | |
|---|---|---|---|---|---|---|
| Declarative manifest | Y | - | - | Y | - | Y |
| Lockfile | Y | Y | - | Y | - | Y |
| R version management | Y | - | - | - | Y | Y |
| Run scripts in isolated env | Y | - | - | - | - | Y |
| CRAN packages | Y | Y | Y | Y | - | Y* |
| Bioconductor packages | Y | Y | Y | Y | - | Y* |
| GitHub packages | Y | Y | Y | Y | - | - |
| Pre-built binaries (P3M) | Y | - | Y | - | - | - |
| System dep detection (Linux) | Y | - | Y | - | - | Y |
| Single config file | Y | - | - | Y | - | Y |
CI mode (--frozen) |
Y | Y | - | - | - | Y |
| No admin rights required | Y | Y | Y | Y | -** | Y |
| Single static binary | Y | - | - | Y | Y | - |
| Windows support | Y | Y | Y | Y | Y | Y |
* pixi installs R packages from conda-forge, not CRAN/Bioconductor directly. ** rig requires admin rights on Windows.
Cold-install wall time (empty library -> all packages installed). P3M binaries for all tools. Median of 3 runs on Apple Silicon.
| Scenario | Packages | uvr sync | install.packages | Speedup |
|---|---|---|---|---|
| ggplot2 | 17 | 0.5s | 13.9s | ~28x |
| tidyverse | 99 | 1.6s | 6.8s | ~4x |
Run
bash benchmarks/bench.shto reproduce. Results vary by machine and network.
- Blazing fast — installs from pre-built P3M binaries; compiles from source only when needed
- Reproducible —
uvr.lockis the source of truth;uvr syncis always idempotent - Project-isolated — every project gets its own
.uvr/library/, never touching system R - Full R version management —
uvr r install 4.4.2,uvr r use >=4.3,uvr r pin 4.4.2 - CRAN + Bioconductor + GitHub —
uvr add DESeq2 --bioc,uvr add user/repo@main - CI-ready —
uvr sync --frozenfails fast if the lockfile is stale; respectsNO_COLOR - Cross-platform — macOS, Linux, and Windows with pre-built binaries for all three
- Written in Rust — single static binary, no R or Python required to install
Download the latest release for your platform from GitHub Releases:
# macOS (Apple Silicon)
curl -fsSL https://github.com/nbafrank/uvr/releases/latest/download/uvr-aarch64-apple-darwin.tar.gz | tar xz
sudo mv uvr /usr/local/bin/
# macOS (Intel)
curl -fsSL https://github.com/nbafrank/uvr/releases/latest/download/uvr-x86_64-apple-darwin.tar.gz | tar xz
sudo mv uvr /usr/local/bin/
# Linux (x86-64)
curl -fsSL https://github.com/nbafrank/uvr/releases/latest/download/uvr-x86_64-unknown-linux-gnu.tar.gz | tar xz
sudo mv uvr /usr/local/bin/
# Linux (ARM64)
curl -fsSL https://github.com/nbafrank/uvr/releases/latest/download/uvr-aarch64-unknown-linux-gnu.tar.gz | tar xz
sudo mv uvr /usr/local/bin/On Windows, download uvr-x86_64-pc-windows-msvc.zip from the releases page and add uvr.exe to your PATH.
The companion R package can install the binary for you:
# Install the R package
install.packages("uvr", repos = NULL, type = "source",
INSTALL_opts = "--no-multiarch")
# Or from the repo:
# install.packages("path/to/r-package", repos = NULL, type = "source")
# Download and install the uvr binary
uvr::install_uvr()From source (requires Rust)
cargo install --git https://github.com/nbafrank/uvr# Create a new project
uvr init my-project --r-version ">=4.3.0"
cd my-project
# Add packages (CRAN, Bioconductor, GitHub)
uvr add ggplot2 dplyr
uvr add DESeq2 --bioc
uvr add tidymodels@>=1.0.0
uvr add user/repo@main
# Install everything from the lockfile
uvr sync
# Run a script in the isolated environment
uvr run analysis.R -- --input data.csv
# See what you have
uvr tree| Command | Description |
|---|---|
uvr init [name] |
Create uvr.toml and .uvr/library/ in the current directory |
uvr add <pkg...> |
Add packages, update manifest + lockfile, install |
uvr remove <pkg...> |
Remove packages from manifest and re-lock |
uvr sync |
Install all packages from the lockfile |
uvr sync --frozen |
Like sync, but fail if the lockfile is stale (CI mode) |
uvr update [pkg...] |
Upgrade packages to latest allowed versions |
uvr update --dry-run |
Show what would change without installing |
uvr lock |
Re-resolve all deps and update uvr.lock without installing |
uvr lock --upgrade |
Upgrade all packages to their latest allowed versions |
uvr tree |
Show the dependency tree |
uvr tree --depth 1 |
Show only direct dependencies |
uvr run [script.R] |
Run a script (or interactive R) with the project library active |
uvr run --with pkg |
Run with extra packages available (not added to manifest) |
uvr r install <ver> |
Download and install a specific R version to ~/.uvr/r-versions/ |
uvr r list |
Show installed R versions |
uvr r list --all |
Show all available R versions (fetched from CRAN) |
uvr r use <ver> |
Set R version constraint in uvr.toml |
uvr r pin <ver> |
Write exact version to .r-version |
uvr export |
Export lockfile to renv.lock format |
uvr export -o renv.lock |
Export to a file |
uvr self-update |
Update uvr itself to the latest GitHub release |
uvr doctor |
Diagnose environment issues (R, build tools, project status) |
uvr completions <shell> |
Generate shell completions (bash, zsh, fish, powershell) |
uvr cache clean |
Remove all cached package downloads |
Generate and install completions for your shell:
# Zsh
uvr completions zsh > ~/.zfunc/_uvr
# Bash
uvr completions bash > /etc/bash_completion.d/uvr
# Fish
uvr completions fish > ~/.config/fish/completions/uvr.fish
# PowerShell
uvr completions powershell > $HOME\Documents\PowerShell\Completions\uvr.ps1uvr can install and manage multiple R versions without sudo or admin rights:
# Install R 4.4.2
uvr r install 4.4.2
# See what's available
uvr r list --all
# Set project constraint (writes to uvr.toml)
uvr r use ">=4.3.0"
# Pin exact version (writes .r-version file)
uvr r pin 4.4.2R versions are installed to ~/.uvr/r-versions/ and managed independently of any system R installation. On Windows, the CRAN installer runs with /CURRENTUSER — no admin elevation required, making it ideal for corporate and university environments where users cannot install software system-wide.
# GitHub Actions example
- name: Install uvr
run: |
curl -fsSL https://github.com/nbafrank/uvr/releases/latest/download/uvr-x86_64-unknown-linux-gnu.tar.gz | tar xz
sudo mv uvr /usr/local/bin/
- name: Install R
run: uvr r install 4.4.2
- name: Install packages (frozen = fail if lockfile is stale)
run: uvr sync --frozen
- name: Run tests
run: uvr run tests/run_tests.Rmy-project/
├── uvr.toml # manifest (commit this)
├── uvr.lock # lockfile (commit this)
├── .r-version # optional exact R pin (commit this)
└── .uvr/
└── library/ # isolated package library (.gitignore this)
[project]
name = "my-project"
r_version = ">=4.3.0"
[dependencies]
ggplot2 = ">=3.0.0"
dplyr = "*"
DESeq2 = { bioc = true }
myPkg = { git = "user/repo", rev = "main" }
[dev-dependencies]
testthat = "*"On Linux, uvr sync automatically checks for missing system libraries using the r-hub sysreqs API and prints the apt-get install command needed:
! Missing system dependencies for 2 package(s):
textshaping requires: libharfbuzz-dev, libfribidi-dev
ragg requires: libfreetype6-dev, libpng-dev
Install with: sudo apt-get install -y libharfbuzz-dev libfribidi-dev libfreetype6-dev libpng-dev
Run uvr doctor to check your setup:
uvr doctor
• Platform: macos/aarch64
• P3M binary packages: available
R installations
✓ R 4.5.3 at ~/.uvr/r-versions/4.5.3/bin/R (managed)
✓ R 4.4.2 at ~/.uvr/r-versions/4.4.2/bin/R (managed)
→ Active R: 4.5.3
Build tools
✓ cargo (Rust toolchain): found
✓ Xcode command line tools: found
✓ Homebrew: found
Project
✓ Manifest: uvr.toml
✓ Lockfile: 42 package(s), R 4.5.3
Cache
• 166 file(s), 204.6 MB
✓ No issues found
| Platform | Binary packages | Source install | R version management |
|---|---|---|---|
| macOS ARM64 (Apple Silicon) | P3M | Y | Y |
| macOS x86-64 | P3M | Y | Y |
| Linux x86-64 | - | Y | Y (Ubuntu 22.04+) |
| Linux ARM64 | - | Y | Y (Ubuntu 22.04+) |
| Windows x86-64 | P3M | Y (with Rtools) | Y (no admin required) |
P3M binary packages are sourced from Posit Package Manager. Linux R binaries are sourced from Posit CDN (Ubuntu 22.04+ only); macOS R binaries from CRAN; Windows R from the CRAN Inno Setup installer.
The r-package/ directory contains an R package that wraps the uvr CLI for use from R/RStudio:
uvr::init() # uvr init
uvr::add("ggplot2") # uvr add ggplot2
uvr::sync() # uvr sync
uvr::run("analysis.R") # uvr run analysis.R
uvr::install_uvr() # download + install the uvr binarySee r-package/ for installation instructions.
MIT — see LICENSE.