Skip to content

Self-contained scripts

Introduced in rv v0.23.0

A script can carry its own configuration in a comment block at the top. rv run reads that block, installs what it declares and runs the script against it. There is no project directory to create: no rproject.toml, no rv.lock and no library are written next to the script.

analysis.R
# /// rv
# dependencies = ["dplyr"]
# ///
library(dplyr)
starwars |>
filter(species == "Droid") |>
select(name, height, mass)
Terminal window
rv run analysis.R

The block starts with a line that is exactly # /// rv and ends with a line that is exactly # ///, both at the very beginning of a line. Every line in between is either a bare # or a # followed by a space and the content. Everything after that # (note the space after the #, it is required) is read as TOML, with the same fields as an rproject.toml. Only the first block in the file is used.

You only need to set the fields you care about in the block, the rest is filled in automatically:

FieldDefault
namescript
r_versionThe version passed to --r-version, or the R found on the PATH
repositoriesThe repositories found in your R profile, like rv init does

If no repositories are declared in the block and none can be detected, it will error.

You do not need to use a [project] table by default, everything will be automatically nested. To set a top level field, write the [project] header yourself and keep the top level fields above it, as you would in an rproject.toml:

analysis.R
# /// rv
# sandbox = true
#
# [project]
# dependencies = ["dplyr"]
# ///

rv writes the resolved configuration in the cache, under scripts/, in a directory keyed by the R version, the platform and a hash of the configuration itself. The library of the script is created next to it.

Two scripts declaring the same thing therefore share a library, and running the same script again reuses it. Editing the block gives the script a new directory: the previous one stays in the cache.