3.2 Set-up an renv project

In order resolve and track dependencies of a project, renv needs to discover what the required packages are. Although renv supports discovering dependencies by scanning all files in the project (implicit mode), we strongly advise to define the required dependencies in a DESCRIPTION file, and rely on renv’s explicit mode (see ‘Snapshot types’ in the documentation for details).

To initialize renv for a project where dependencies are explicitly stated in the DESCRIPTION file, run:

renv::init(settings = list(snapshot.type = "explicit"))

This ensures that the dependencies of the projects, listed in the DESCRIPTION file, are considered for initializing the virtual environment.

The renv initialization causes:

  • the creation of the lock-file renv.lock, which tracks the version of the resolved transitive package dependencies, along with the R version and package repositories information;
  • the set-up of renv infrastructure for the project including a specific library, where packages are installed at the versions tracked in renv.lock;
  • the creation of a new renv folder containing:
    • a settings file settings.json,
    • a script activate.R to activate the project-specific virtual environment;
  • the inclusion of the activation script in .Rprofile, which ensures activation upon session start in the project;
  • an update of the .Rbuildignore because the renv-specific files are not part of the R package infrastructure;

Note that, by default, renv will use the repository from Posit Public Package Manager (PPM) CRAN mirror for package installation.

Having all the renv infrastructure committed under version control ensures that the same renv set-up and environment is available to anyone working on the same project.

Upon session startup, renv would detect mismatches between the package versions recorded in renv.lock and those installed in the project library, hinting at actions to ensure consistency. In particular,

renv::status()

would check and provide information about packages whose version is out-of-sync, whereas

renv::restore()

would restore the versions as listed in renv.lock, and is the go-to command to ensure the local environment is always aligned with the locked dependencies.

3.2.1 Development dependencies

By default, development dependencies (like those specified under Suggests: in the DESCRIPTION file), are not included in renv.lock. They can be however included via

renv::snaphot(dev = TRUE)

Note that, given the default behavior with respect to development dependencies, renv might report out-of-sync dependencies upon session startup. Make sure to use

renv::status(dev = TRUE)

if you are included development dependencies in renv.lock.

Given that only packages explicitly mentioned in the DESCRIPTION file are taken care of by renv, additional packages used for development, such as devtools or usethis, should be installed for the specific project via install.packages() or renv::install(), and are never included in the lock-file.

3.2.2 Control package versions

If the DESCRIPTION file does not request a specific package version, renv will use the latest version in the repository, which is always the case for indirect/transitive dependencies. Although the locking mechanism allows to freeze such versions, it might be desirable to have a stricter control over the versions of packages used in a project. To do so, one can leverage the date-based CRAN snapshots provided by PPM, e.g.

# Install all dependencies from a specific CRAN snapshot date on PPM
options(repos = "https://packagemanager.posit.co/cran/2024-01-02")

Date-based CRAN snapshots have built-in support in renv with renv::checkout(), w/o the need for (options(repos = ...)):

# check out packages from PPM using the date '2023-01-02'
renv::checkout(date = "2024-01-02")
# or provide the repos URL explicitly
renv::checkout(repos = "https://packagemanager.posit.co/cran/2024-01-02")

By default, renv::checkout() would ensure packages in the project library are installed from the specific date, w/o updating renv.lock. This implies you will have to run renv::snapshot() to updated the lock-file. As an alternative, you could use the actions argument to control the behavior of renv::checkout(). In particular,

renv::checkout(date = "2023-01-02", actions=c("snapshot", "restore"))

would install packages and lock the corresponding versions (as well as the used repository) at the same time.

Note that renv::checkout() can also be use for a subset of packages (and their transitive dependencies)

renv::checkout(packages = "dplyr", date = "2024-01-02")