{renv}

Create reproducible environments for your R projects

Author
Affiliation

Dave Tang

davetangdotorg

Published

2025-10-15

Keywords

renv, reproducibility

Overview

The renv package helps you create reproducible environments for your R projects. Use renv to make your R projects more isolated, portable and reproducible.

  • Isolated: Installing a new or updated package for one project won’t break your other projects, and vice versa. That’s because renv gives each project its own private library.
  • Portable: Easily transport your projects from one computer to another, even across different platforms. renv makes it easy to install the packages your project depends on.
  • Reproducible: renv records the exact package versions you depend on, and ensures those exact versions are the ones that get installed wherever you go.

Workflow

Use renv::init() to initialise renv in a new or existing project. This will set up a project library, containing all the packages you’re currently using. The packages (and all the metadata needed to reinstall them) are recorded into a lockfile, renv.lock, and a .Rprofile ensures that the library is used every time you open that project.

Documentation for renv::init():

Call renv::init() to start using renv in the current project. This will:

  1. Set up project infrastructure (as described in scaffold()) including the project library and the .Rprofile that ensures renv will be used in all future sessions,
  2. Discover the packages that are currently being used in your project (via dependencies()), and install them into the project library (as described in hydrate()),
  3. Create a lockfile that records the state of the project library so it can be restored by others (as described in snapshot()),
  4. Restart R (if running inside RStudio).

If you call renv::init() with a project that is already using renv, it will attempt to do the right thing: it will restore the project library if it’s missing, or otherwise ask you what to do.

Create a new project using usethis::create_project; {usethis} is a workflow package: it automates repetitive tasks that arise during project setup and development, both for R packages and non-package projects.

here::i_am("renv.qmd")
usethis::create_project(here::here())

Initiate renv.

here::i_am("renv.qmd")
renv::init(project = here::here())

As you continue to work on your project, you will install and upgrade packages, either using install.packages() and update.packages() or renv::install() and renv::update(). After you’ve confirmed your code works as expected, use renv::snapshot() to record the packages and their sources in the lockfile.

Later, if you need to share your code with someone else or run your code on new machine, your collaborator (or you) can call renv::restore() to reinstall the specific package versions recorded in the lockfile.

Contents of lock file.

here::i_am("renv.qmd")
renv_lock <- yaml::read_yaml(paste0(here::here(), '/renv.lock'))
str(renv_lock, max.level = 2)
List of 2
 $ R       :List of 2
  ..$ Version     : chr "4.5.0"
  ..$ Repositories:List of 1
 $ Packages:List of 40
  ..$ R6         :List of 19
  ..$ Rcpp       :List of 19
  ..$ base64enc  :List of 14
  ..$ bslib      :List of 25
  ..$ cachem     :List of 19
  ..$ cli        :List of 20
  ..$ commonmark :List of 18
  ..$ crayon     :List of 19
  ..$ digest     :List of 19
  ..$ evaluate   :List of 20
  ..$ fastmap    :List of 16
  ..$ fontawesome:List of 21
  ..$ fs         :List of 25
  ..$ glue       :List of 22
  ..$ here       :List of 21
  ..$ highr      :List of 20
  ..$ htmltools  :List of 23
  ..$ httpuv     :List of 22
  ..$ jquerylib  :List of 16
  ..$ jsonlite   :List of 18
  ..$ knitr      :List of 22
  ..$ later      :List of 20
  ..$ lifecycle  :List of 21
  ..$ magrittr   :List of 21
  ..$ memoise    :List of 17
  ..$ mime       :List of 17
  ..$ promises   :List of 24
  ..$ rappdirs   :List of 20
  ..$ renv       :List of 23
  ..$ rlang      :List of 24
  ..$ rmarkdown  :List of 23
  ..$ rprojroot  :List of 19
  ..$ sass       :List of 21
  ..$ shiny      :List of 23
  ..$ sourcetools:List of 16
  ..$ tinytex    :List of 18
  ..$ withr      :List of 22
  ..$ xfun       :List of 20
  ..$ xtable     :List of 18
  ..$ yaml       :List of 16

Search paths for packages.

.libPaths()
[1] "/home/rstudio/work/learning_renv/renv/library/linux-ubuntu-noble/R-4.5/x86_64-pc-linux-gnu"
[2] "/home/rstudio/.cache/R/renv/sandbox/linux-ubuntu-noble/R-4.5/x86_64-pc-linux-gnu/25ebdc09" 
  • Run renv::status() to report inconsistencies between lockfile, library, and dependencies.
  • Run renv::snapshot() to record current state of the project library in the lockfile.

Caching

If you use renv for multiple projects, you’ll have multiple libraries, meaning that you’ll often need to install the same package in multiple places. It would be annoying if you had to download (or worse, compile) the package repeatedly, so renv uses a package cache. That means you only ever have to download and install a package once, and for each subsequent install, renv will just add a link from the project library to the global cache. You can learn more about the cache in vignette(“package-install”).

One of renv’s primary features is the global package cache, which shared across all projects. The renv package cache provides two primary benefits:

  1. Installing and restoring packages is much faster, as renv can find and re-use previously installed packages from the cache.
  2. Projects take up less disk space, because each project doesn’t need to contain it’s own copy of every package.

When installing a package, renv installs into the global cache and then adds a symlink to that directory in the project library. That way each renv project remains isolated from other projects on your system, but they can still re-use the same installed packages.

The process by which packages enter the cache is roughly as follows:

  1. Package installation is requested via e.g. install.packages(), or renv::install(), or as part of renv::restore().
  2. If renv is able to find the requested version of the package in the cache, then that package is linked into the project library, and installation is complete.
  3. Otherwise, the package is downloaded and installed into the project library.
  4. After installation of the package has successfully completed, the package is then copied into the global package cache, and then symlinked into the project library.

In some cases, renv will be unable to directly link from the global package cache to your project library, e.g. if the package cache and your project library live on different disk volumes. In such a case, renv will instead copy the package from the cache into the project library. This is much slower, so is worth avoiding.

Cache location

You can find the location of the current cache with renv::paths$cache().

renv::paths$cache()
[1] "/home/rstudio/.cache/R/renv/cache/v5/linux-ubuntu-noble/R-4.5/x86_64-pc-linux-gnu"

List contents of cache.

list.files(renv::paths$cache())
 [1] "base64enc"   "bslib"       "cachem"      "cli"         "commonmark" 
 [6] "crayon"      "digest"      "evaluate"    "fastmap"     "fontawesome"
[11] "fs"          "glue"        "here"        "highr"       "htmltools"  
[16] "httpuv"      "jquerylib"   "jsonlite"    "knitr"       "later"      
[21] "lifecycle"   "magrittr"    "memoise"     "mime"        "promises"   
[26] "R6"          "rappdirs"    "Rcpp"        "rlang"       "rmarkdown"  
[31] "rprojroot"   "sass"        "shiny"       "sourcetools" "tinytex"    
[36] "withr"       "xfun"        "xtable"      "yaml"       

List contents of cache for the {here} package.

list.files(paste0(renv::paths$cache(), '/here'), recursive = TRUE)
 [1] "1.0.1/24b224366f9c2e7534d2344d10d59211/here/demo-project/analysis/report.Rmd"          
 [2] "1.0.1/24b224366f9c2e7534d2344d10d59211/here/demo-project/data/penguins.csv"            
 [3] "1.0.1/24b224366f9c2e7534d2344d10d59211/here/demo-project/demo-project.Rproj"           
 [4] "1.0.1/24b224366f9c2e7534d2344d10d59211/here/demo-project/prepare/penguins.R"           
 [5] "1.0.1/24b224366f9c2e7534d2344d10d59211/here/DESCRIPTION"                               
 [6] "1.0.1/24b224366f9c2e7534d2344d10d59211/here/doc/here.html"                             
 [7] "1.0.1/24b224366f9c2e7534d2344d10d59211/here/doc/here.R"                                
 [8] "1.0.1/24b224366f9c2e7534d2344d10d59211/here/doc/here.Rmd"                              
 [9] "1.0.1/24b224366f9c2e7534d2344d10d59211/here/doc/index.html"                            
[10] "1.0.1/24b224366f9c2e7534d2344d10d59211/here/doc/rmarkdown.html"                        
[11] "1.0.1/24b224366f9c2e7534d2344d10d59211/here/doc/rmarkdown.R"                           
[12] "1.0.1/24b224366f9c2e7534d2344d10d59211/here/doc/rmarkdown.Rmd"                         
[13] "1.0.1/24b224366f9c2e7534d2344d10d59211/here/help/aliases.rds"                          
[14] "1.0.1/24b224366f9c2e7534d2344d10d59211/here/help/AnIndex"                              
[15] "1.0.1/24b224366f9c2e7534d2344d10d59211/here/help/figures/lifecycle-archived.svg"       
[16] "1.0.1/24b224366f9c2e7534d2344d10d59211/here/help/figures/lifecycle-defunct.svg"        
[17] "1.0.1/24b224366f9c2e7534d2344d10d59211/here/help/figures/lifecycle-deprecated.svg"     
[18] "1.0.1/24b224366f9c2e7534d2344d10d59211/here/help/figures/lifecycle-experimental.svg"   
[19] "1.0.1/24b224366f9c2e7534d2344d10d59211/here/help/figures/lifecycle-maturing.svg"       
[20] "1.0.1/24b224366f9c2e7534d2344d10d59211/here/help/figures/lifecycle-questioning.svg"    
[21] "1.0.1/24b224366f9c2e7534d2344d10d59211/here/help/figures/lifecycle-soft-deprecated.svg"
[22] "1.0.1/24b224366f9c2e7534d2344d10d59211/here/help/figures/lifecycle-stable.svg"         
[23] "1.0.1/24b224366f9c2e7534d2344d10d59211/here/help/figures/lifecycle-superseded.svg"     
[24] "1.0.1/24b224366f9c2e7534d2344d10d59211/here/help/here.rdb"                             
[25] "1.0.1/24b224366f9c2e7534d2344d10d59211/here/help/here.rdx"                             
[26] "1.0.1/24b224366f9c2e7534d2344d10d59211/here/help/paths.rds"                            
[27] "1.0.1/24b224366f9c2e7534d2344d10d59211/here/html/00Index.html"                         
[28] "1.0.1/24b224366f9c2e7534d2344d10d59211/here/html/R.css"                                
[29] "1.0.1/24b224366f9c2e7534d2344d10d59211/here/INDEX"                                     
[30] "1.0.1/24b224366f9c2e7534d2344d10d59211/here/LICENSE"                                   
[31] "1.0.1/24b224366f9c2e7534d2344d10d59211/here/Meta/features.rds"                         
[32] "1.0.1/24b224366f9c2e7534d2344d10d59211/here/Meta/hsearch.rds"                          
[33] "1.0.1/24b224366f9c2e7534d2344d10d59211/here/Meta/links.rds"                            
[34] "1.0.1/24b224366f9c2e7534d2344d10d59211/here/Meta/nsInfo.rds"                           
[35] "1.0.1/24b224366f9c2e7534d2344d10d59211/here/Meta/package.rds"                          
[36] "1.0.1/24b224366f9c2e7534d2344d10d59211/here/Meta/Rd.rds"                               
[37] "1.0.1/24b224366f9c2e7534d2344d10d59211/here/Meta/vignette.rds"                         
[38] "1.0.1/24b224366f9c2e7534d2344d10d59211/here/NAMESPACE"                                 
[39] "1.0.1/24b224366f9c2e7534d2344d10d59211/here/NEWS.md"                                   
[40] "1.0.1/24b224366f9c2e7534d2344d10d59211/here/R/here"                                    
[41] "1.0.1/24b224366f9c2e7534d2344d10d59211/here/R/here.rdb"                                
[42] "1.0.1/24b224366f9c2e7534d2344d10d59211/here/R/here.rdx"                                
[43] "1.0.1/24b224366f9c2e7534d2344d10d59211/here/WORDLIST"                                  

If you’d like to share the package cache across multiple users, you can do so by setting the RENV_PATHS_CACHE environment variable to a shared path. This variable should be set in an R startup file to make it apply to all R sessions. While you can set it in a project-local .Renviron, or the user-level ~/.Renviron, we generally recommend using the R installation’s site-wide Renviron.site if you’d like to ensure the same cache path is visible to all users of R on a system.

You may also want to set RENV_PATHS_CACHE so that the global package cache can be stored on the same volume as the projects you normally work on. This is especially important when working projects stored on a networked filesystem.

Multiple caches

It is also possible to configure renv to use multiple cache locations. For example, you might want to make both a user-local package cache, as well as a global administrator-managed cache, visible within an renv project. To do so, you can specify the paths to the cache separated with a ; (or : on Unix if preferred). For example:

RENV_PATHS_CACHE=/path/to/local/cache;/path/to/global/cache

In such a case, renv will iterate over the cache locations in order when trying to find a package, and newly-installed packages will enter the first writable cache path listed in RENV_PATHS_CACHE.

Shared cache locations

When the renv cache is enabled, if that cache is shared and visible to multiple users, then each of those users will have an opportunity to install packages into the renv cache. However, some care must be taken to ensure that these packages can be used by different users in your environment:

  1. Packages copied into the cache may have Access-control Lists (ACLs), which might prevent others from using packages that have been installed into the cache. If this is the case, it’s important that ACLs be set (or updated) on cache entries so that the cache is accessible to each user requiring access. When deploying renv in an enterprise environment, the system administrator should take care to ensure ACLs (if any) allow users access to packages within the renv cache.
  2. By default, packages copied into the cache will remain “owned” by the user that requested installation of that package. If you’d like renv to instead re-assign ownership of the cached package to a separate user account, you can set the RENV_CACHE_USER environment variable. When set, renv will attempt to run chown -R <package> <user> to update cache ownership after the package has been copied into the cache.

Caveats

While we recommend enabling the cache by default, if you’re having trouble with it, you can disable it by setting the project setting renv::settings$use.cache(FALSE). Doing this will ensure that packages are then installed into your project library directly, without attempting to link and use packages from the renv cache.

If you find a problematic package has entered the cache (for example, an installed package has become corrupted), that package can be removed with the renv::purge() function. See the ?purge documentation for caveats and things to be aware of when removing packages from the cache.

You can also force a package to be re-installed and re-cached with the following functions:

# restore packages from the lockfile, bypassing the cache
renv::restore(rebuild = TRUE)

# re-install a package
renv::install("<package>", rebuild = TRUE)

# rebuild all packages in the project
renv::rebuild()

Reuse

CC-BY 4.0