8  Robust Environments: {renv}

intermediate
Summary

In this chapter you will learn how your reproducible research project becomes robust against different package versions. You will make it easy for you to and collaborators to use the same package versions in your joint project.

8.1 Introduction

Now a project is well-named including its files and folders. It is well-structured and follows a community standard as Psych-DS. It follows the FAIR principles. The code is written in the tidyverse-style. Is it reproducible? Well, it may be. Very likely, it is not. However, we have done a great job in organizing our research project. The previous chapters dealt with a possible architecture of a reproducible research project. But still, there are things to improve. The next chapter will deal with reproducible computational environments. For an introduction, read the example below:

Imagine you need to reproduce the results of a research article from 2019. The project structure is openly available at OSF or at Zenodo. You find a nice structure, run a script but then you get an error message in R like:

Output
Error in function_name(object[[i]], ...) : could not find function "function_name"

R is telling you that it cannot find a function called function_name. A similar problem can be that only arguments of a function are not found. However, the script runs correctly at the device of the researcher writing the script. Thus, you are facing a research project that is only reproducible on the same device it was written on. A possible reason is that your computational environment differs from the environment of the other researcher. You might have installed different versions of R packages or of itself.

Computational environments include everything associated with technical infrastructure and software for conducting data analyses and reproducing scientific results. This comprises operating systems (Apple, Windows, Linux), software versions (R 4.3.1, 4.4.1, 4.4.2, etc.), and different versions of packages (dplyr 0.8.0, 1.1.4). It is important to consider your computational environment when it comes to computational reproducibility. The longer the time interval between creation and reproduction of your code is, the more likely reproducibility is not possible because of different computational environments. Software progresses over time, which is good in general. However, different versions of software include that some functions will not work in future versions or will do different things. Thus, it is important to keep track of the computational environment during creation of code and analyses.

This done by so called Package Management Systems. Package Management Systems install and keep track of software and software versions, export files that specify these required software packages/versions and that can be shared with others (The Turing Way Community 2022). Thus, environments can be replicated, either manually or via the Package Management System. In this chapter, we will introduce the Package Mangament System {renv}.

Different computational environments can hinder computational reproducibility. In the example above, the code cannot be executed. However, sometimes package updates do only change the calculation of a function or an argument. Thus, a different package version leads to different results even though the code runs correctly.

Problems of different computational environments
  • scripts could stop running because of different functions or arguments
  • scripts could run correctly but produce different results
How renv helps aligning computational environments

With renv

  • package versions can be safed inside a research project
  • collaborators can easily load the same package versions independent of their device
  • R projects become isolated, portable and reproducible (Ushey and Wickham 2024)

8.2 renv

renv is a package that cares about the different versions of your used packages. To get the most out of this chapter, we encourage you to create a new test project in RStudio where you can try out the functions that you are about to learn. To use renv as package dependency manager, you only need to install it, as every other package in .

Console
install.packages("renv")
Benefits of renv
  • easy documenting package versions
  • easy restoring of older package versions

8.2.1 renv-functions

The renv package is very powerful because it does a lot of useful things while only needing 4 (+1) functions. Before we start, it is helpful to disentangle a couple of terms. A library is a directory containing multiple packages. This is confusing because you load packages with the command library(package). The command does not load a library, but a package. Until now you install packages into your System library with install.packages("package") and load these packages within this library with library(package). Packages in the system library are independent from your project. With renv, we will start to use project libraries. Thus, we will install and use packages to a library that meets the requirement for your specific projects. However, it might occur that you have to install the same packages multiple times when you want to use them across multiple projects.

8.2.1.1 renv::init

When you start using renv, we recommend you to set up an R-project before. If you do not know how to do that, see Section 7.1. With renv::init(), we initialize our reproducible, computational environment. With this command, a couple of files and folders are created.

  • .Rprofile is a file that automatically runs every time you start your R-project. renv uses it to set up your project library. Thus, once you have turned on your project library, it remains active until you turn it off.

  • renv/library contains all the packages you are currently using. This is now your project library. With different libraries for different projects you have the benefit of isolation. When a package version changes in one project, it does not affect your other projects.

  • The lockfile renv.lock contains all the metadata of your packages to reinstall it on a new machine. It serves as documentation about which package and which version of the packages you use. It also displays the R version used in your particular project.

Click here to view the full renv.lock file of this project.
renv.lock
{
  "R": {
    "Version": "4.4.1",
    "Repositories": [
      {
        "Name": "CRAN",
        "URL": "https://packagemanager.posit.co/cran/latest"
      }
    ]
  },
  "Packages": {
    "MASS": {
      "Package": "MASS",
      "Version": "7.3-61",
      "Source": "Repository",
      "Repository": "CRAN",
      "Requirements": [
        "R",
        "grDevices",
        "graphics",
        "methods",
        "stats",
        "utils"
      ],
      "Hash": "0cafd6f0500e5deba33be22c46bf6055"
    },
    "R6": {
      "Package": "R6",
      "Version": "2.5.1",
      "Source": "Repository",
      "Repository": "CRAN",
      "Requirements": [
        "R"
      ],
      "Hash": "470851b6d5d0ac559e9d01bb352b4021"
    },
    "assertr": {
      "Package": "assertr",
      "Version": "3.0.1",
      "Source": "Repository",
      "Repository": "CRAN",
      "Requirements": [
        "MASS",
        "R",
        "dplyr",
        "methods",
        "rlang",
        "stats",
        "utils"
      ],
      "Hash": "dd34511e88d11c95e80f8d9bb0606e79"
    },
    "backports": {
      "Package": "backports",
      "Version": "1.5.0",
      "Source": "Repository",
      "Repository": "CRAN",
      "Requirements": [
        "R"
      ],
      "Hash": "e1e1b9d75c37401117b636b7ae50827a"
    },
    "base64enc": {
      "Package": "base64enc",
      "Version": "0.1-3",
      "Source": "Repository",
      "Repository": "CRAN",
      "Requirements": [
        "R"
      ],
      "Hash": "543776ae6848fde2f48ff3816d0628bc"
    },
    "bslib": {
      "Package": "bslib",
      "Version": "0.8.0",
      "Source": "Repository",
      "Repository": "RSPM",
      "Requirements": [
        "R",
        "base64enc",
        "cachem",
        "fastmap",
        "grDevices",
        "htmltools",
        "jquerylib",
        "jsonlite",
        "lifecycle",
        "memoise",
        "mime",
        "rlang",
        "sass"
      ],
      "Hash": "b299c6741ca9746fb227debcb0f9fb6c"
    },
    "cachem": {
      "Package": "cachem",
      "Version": "1.1.0",
      "Source": "Repository",
      "Repository": "RSPM",
      "Requirements": [
        "fastmap",
        "rlang"
      ],
      "Hash": "cd9a672193789068eb5a2aad65a0dedf"
    },
    "callr": {
      "Package": "callr",
      "Version": "3.7.6",
      "Source": "Repository",
      "Repository": "CRAN",
      "Requirements": [
        "R",
        "R6",
        "processx",
        "utils"
      ],
      "Hash": "d7e13f49c19103ece9e58ad2d83a7354"
    },
    "cli": {
      "Package": "cli",
      "Version": "3.6.3",
      "Source": "Repository",
      "Repository": "RSPM",
      "Requirements": [
        "R",
        "utils"
      ],
      "Hash": "b21916dd77a27642b447374a5d30ecf3"
    },
    "codetools": {
      "Package": "codetools",
      "Version": "0.2-20",
      "Source": "Repository",
      "Repository": "CRAN",
      "Requirements": [
        "R"
      ],
      "Hash": "61e097f35917d342622f21cdc79c256e"
    },
    "cpp11": {
      "Package": "cpp11",
      "Version": "0.5.0",
      "Source": "Repository",
      "Repository": "CRAN",
      "Requirements": [
        "R"
      ],
      "Hash": "91570bba75d0c9d3f1040c835cee8fba"
    },
    "crayon": {
      "Package": "crayon",
      "Version": "1.5.3",
      "Source": "Repository",
      "Repository": "CRAN",
      "Requirements": [
        "grDevices",
        "methods",
        "utils"
      ],
      "Hash": "859d96e65ef198fd43e82b9628d593ef"
    },
    "cyclocomp": {
      "Package": "cyclocomp",
      "Version": "1.1.1",
      "Source": "Repository",
      "Repository": "CRAN",
      "Requirements": [
        "callr",
        "crayon",
        "desc",
        "remotes",
        "withr"
      ],
      "Hash": "cdc4a473222b0112d4df0bcfbed12d44"
    },
    "data.table": {
      "Package": "data.table",
      "Version": "1.16.2",
      "Source": "Repository",
      "Repository": "RSPM",
      "Requirements": [
        "R",
        "methods"
      ],
      "Hash": "2e00b378fc3be69c865120d9f313039a"
    },
    "desc": {
      "Package": "desc",
      "Version": "1.4.3",
      "Source": "Repository",
      "Repository": "CRAN",
      "Requirements": [
        "R",
        "R6",
        "cli",
        "utils"
      ],
      "Hash": "99b79fcbd6c4d1ce087f5c5c758b384f"
    },
    "digest": {
      "Package": "digest",
      "Version": "0.6.37",
      "Source": "Repository",
      "Repository": "CRAN",
      "Requirements": [
        "R",
        "utils"
      ],
      "Hash": "33698c4b3127fc9f506654607fb73676"
    },
    "dplyr": {
      "Package": "dplyr",
      "Version": "1.1.4",
      "Source": "Repository",
      "Repository": "RSPM",
      "Requirements": [
        "R",
        "R6",
        "cli",
        "generics",
        "glue",
        "lifecycle",
        "magrittr",
        "methods",
        "pillar",
        "rlang",
        "tibble",
        "tidyselect",
        "utils",
        "vctrs"
      ],
      "Hash": "fedd9d00c2944ff00a0e2696ccf048ec"
    },
    "evaluate": {
      "Package": "evaluate",
      "Version": "1.0.1",
      "Source": "Repository",
      "Repository": "RSPM",
      "Requirements": [
        "R"
      ],
      "Hash": "3fd29944b231036ad67c3edb32e02201"
    },
    "fansi": {
      "Package": "fansi",
      "Version": "1.0.6",
      "Source": "Repository",
      "Repository": "CRAN",
      "Requirements": [
        "R",
        "grDevices",
        "utils"
      ],
      "Hash": "962174cf2aeb5b9eea581522286a911f"
    },
    "fastmap": {
      "Package": "fastmap",
      "Version": "1.2.0",
      "Source": "Repository",
      "Repository": "CRAN",
      "Hash": "aa5e1cd11c2d15497494c5292d7ffcc8"
    },
    "fontawesome": {
      "Package": "fontawesome",
      "Version": "0.5.3",
      "Source": "Repository",
      "Repository": "CRAN",
      "Requirements": [
        "R",
        "htmltools",
        "rlang"
      ],
      "Hash": "bd1297f9b5b1fc1372d19e2c4cd82215"
    },
    "fs": {
      "Package": "fs",
      "Version": "1.6.5",
      "Source": "Repository",
      "Repository": "RSPM",
      "Requirements": [
        "R",
        "methods"
      ],
      "Hash": "7f48af39fa27711ea5fbd183b399920d"
    },
    "generics": {
      "Package": "generics",
      "Version": "0.1.3",
      "Source": "Repository",
      "Repository": "CRAN",
      "Requirements": [
        "R",
        "methods"
      ],
      "Hash": "15e9634c0fcd294799e9b2e929ed1b86"
    },
    "glue": {
      "Package": "glue",
      "Version": "1.8.0",
      "Source": "Repository",
      "Repository": "RSPM",
      "Requirements": [
        "R",
        "methods"
      ],
      "Hash": "5899f1eaa825580172bb56c08266f37c"
    },
    "here": {
      "Package": "here",
      "Version": "1.0.1",
      "Source": "Repository",
      "Repository": "CRAN",
      "Requirements": [
        "rprojroot"
      ],
      "Hash": "24b224366f9c2e7534d2344d10d59211"
    },
    "highr": {
      "Package": "highr",
      "Version": "0.11",
      "Source": "Repository",
      "Repository": "RSPM",
      "Requirements": [
        "R",
        "xfun"
      ],
      "Hash": "d65ba49117ca223614f71b60d85b8ab7"
    },
    "htmltools": {
      "Package": "htmltools",
      "Version": "0.5.8.1",
      "Source": "Repository",
      "Repository": "RSPM",
      "Requirements": [
        "R",
        "base64enc",
        "digest",
        "fastmap",
        "grDevices",
        "rlang",
        "utils"
      ],
      "Hash": "81d371a9cc60640e74e4ab6ac46dcedc"
    },
    "htmlwidgets": {
      "Package": "htmlwidgets",
      "Version": "1.6.4",
      "Source": "Repository",
      "Repository": "CRAN",
      "Requirements": [
        "grDevices",
        "htmltools",
        "jsonlite",
        "knitr",
        "rmarkdown",
        "yaml"
      ],
      "Hash": "04291cc45198225444a397606810ac37"
    },
    "jquerylib": {
      "Package": "jquerylib",
      "Version": "0.1.4",
      "Source": "Repository",
      "Repository": "CRAN",
      "Requirements": [
        "htmltools"
      ],
      "Hash": "5aab57a3bd297eee1c1d862735972182"
    },
    "jsonlite": {
      "Package": "jsonlite",
      "Version": "1.8.9",
      "Source": "Repository",
      "Repository": "RSPM",
      "Requirements": [
        "methods"
      ],
      "Hash": "4e993b65c2c3ffbffce7bb3e2c6f832b"
    },
    "knitr": {
      "Package": "knitr",
      "Version": "1.49",
      "Source": "Repository",
      "Repository": "CRAN",
      "Requirements": [
        "R",
        "evaluate",
        "highr",
        "methods",
        "tools",
        "xfun",
        "yaml"
      ],
      "Hash": "9fcb189926d93c636dea94fbe4f44480"
    },
    "lazyeval": {
      "Package": "lazyeval",
      "Version": "0.2.2",
      "Source": "Repository",
      "Repository": "CRAN",
      "Requirements": [
        "R"
      ],
      "Hash": "d908914ae53b04d4c0c0fd72ecc35370"
    },
    "lifecycle": {
      "Package": "lifecycle",
      "Version": "1.0.4",
      "Source": "Repository",
      "Repository": "RSPM",
      "Requirements": [
        "R",
        "cli",
        "glue",
        "rlang"
      ],
      "Hash": "b8552d117e1b808b09a832f589b79035"
    },
    "lintr": {
      "Package": "lintr",
      "Version": "3.1.2",
      "Source": "Repository",
      "Repository": "CRAN",
      "Requirements": [
        "R",
        "backports",
        "codetools",
        "cyclocomp",
        "digest",
        "glue",
        "knitr",
        "rex",
        "stats",
        "utils",
        "xml2",
        "xmlparsedata"
      ],
      "Hash": "08cff46381a242d44c0d8dd0aabd9f71"
    },
    "magrittr": {
      "Package": "magrittr",
      "Version": "2.0.3",
      "Source": "Repository",
      "Repository": "CRAN",
      "Requirements": [
        "R"
      ],
      "Hash": "7ce2733a9826b3aeb1775d56fd305472"
    },
    "memoise": {
      "Package": "memoise",
      "Version": "2.0.1",
      "Source": "Repository",
      "Repository": "CRAN",
      "Requirements": [
        "cachem",
        "rlang"
      ],
      "Hash": "e2817ccf4a065c5d9d7f2cfbe7c1d78c"
    },
    "mime": {
      "Package": "mime",
      "Version": "0.12",
      "Source": "Repository",
      "Repository": "CRAN",
      "Requirements": [
        "tools"
      ],
      "Hash": "18e9c28c1d3ca1560ce30658b22ce104"
    },
    "pillar": {
      "Package": "pillar",
      "Version": "1.9.0",
      "Source": "Repository",
      "Repository": "CRAN",
      "Requirements": [
        "cli",
        "fansi",
        "glue",
        "lifecycle",
        "rlang",
        "utf8",
        "utils",
        "vctrs"
      ],
      "Hash": "15da5a8412f317beeee6175fbc76f4bb"
    },
    "pkgconfig": {
      "Package": "pkgconfig",
      "Version": "2.0.3",
      "Source": "Repository",
      "Repository": "CRAN",
      "Requirements": [
        "utils"
      ],
      "Hash": "01f28d4278f15c76cddbea05899c5d6f"
    },
    "processx": {
      "Package": "processx",
      "Version": "3.8.4",
      "Source": "Repository",
      "Repository": "CRAN",
      "Requirements": [
        "R",
        "R6",
        "ps",
        "utils"
      ],
      "Hash": "0c90a7d71988856bad2a2a45dd871bb9"
    },
    "ps": {
      "Package": "ps",
      "Version": "1.8.1",
      "Source": "Repository",
      "Repository": "CRAN",
      "Requirements": [
        "R",
        "utils"
      ],
      "Hash": "b4404b1de13758dea1c0484ad0d48563"
    },
    "purrr": {
      "Package": "purrr",
      "Version": "1.0.2",
      "Source": "Repository",
      "Repository": "CRAN",
      "Requirements": [
        "R",
        "cli",
        "lifecycle",
        "magrittr",
        "rlang",
        "vctrs"
      ],
      "Hash": "1cba04a4e9414bdefc9dcaa99649a8dc"
    },
    "rappdirs": {
      "Package": "rappdirs",
      "Version": "0.3.3",
      "Source": "Repository",
      "Repository": "CRAN",
      "Requirements": [
        "R"
      ],
      "Hash": "5e3c5dc0b071b21fa128676560dbe94d"
    },
    "remotes": {
      "Package": "remotes",
      "Version": "2.5.0",
      "Source": "Repository",
      "Repository": "CRAN",
      "Requirements": [
        "R",
        "methods",
        "stats",
        "tools",
        "utils"
      ],
      "Hash": "3ee025083e66f18db6cf27b56e23e141"
    },
    "renv": {
      "Package": "renv",
      "Version": "1.0.11",
      "Source": "Repository",
      "Repository": "RSPM",
      "Requirements": [
        "utils"
      ],
      "Hash": "47623f66b4e80b3b0587bc5d7b309888"
    },
    "rex": {
      "Package": "rex",
      "Version": "1.2.1",
      "Source": "Repository",
      "Repository": "CRAN",
      "Requirements": [
        "lazyeval"
      ],
      "Hash": "ae34cd56890607370665bee5bd17812f"
    },
    "rlang": {
      "Package": "rlang",
      "Version": "1.1.4",
      "Source": "Repository",
      "Repository": "RSPM",
      "Requirements": [
        "R",
        "utils"
      ],
      "Hash": "3eec01f8b1dee337674b2e34ab1f9bc1"
    },
    "rmarkdown": {
      "Package": "rmarkdown",
      "Version": "2.29",
      "Source": "Repository",
      "Repository": "CRAN",
      "Requirements": [
        "R",
        "bslib",
        "evaluate",
        "fontawesome",
        "htmltools",
        "jquerylib",
        "jsonlite",
        "knitr",
        "methods",
        "tinytex",
        "tools",
        "utils",
        "xfun",
        "yaml"
      ],
      "Hash": "df99277f63d01c34e95e3d2f06a79736"
    },
    "rprojroot": {
      "Package": "rprojroot",
      "Version": "2.0.4",
      "Source": "Repository",
      "Repository": "CRAN",
      "Requirements": [
        "R"
      ],
      "Hash": "4c8415e0ec1e29f3f4f6fc108bef0144"
    },
    "sass": {
      "Package": "sass",
      "Version": "0.4.9",
      "Source": "Repository",
      "Repository": "RSPM",
      "Requirements": [
        "R6",
        "fs",
        "htmltools",
        "rappdirs",
        "rlang"
      ],
      "Hash": "d53dbfddf695303ea4ad66f86e99b95d"
    },
    "stringi": {
      "Package": "stringi",
      "Version": "1.8.4",
      "Source": "Repository",
      "Repository": "CRAN",
      "Requirements": [
        "R",
        "stats",
        "tools",
        "utils"
      ],
      "Hash": "39e1144fd75428983dc3f63aa53dfa91"
    },
    "stringr": {
      "Package": "stringr",
      "Version": "1.5.1",
      "Source": "Repository",
      "Repository": "CRAN",
      "Requirements": [
        "R",
        "cli",
        "glue",
        "lifecycle",
        "magrittr",
        "rlang",
        "stringi",
        "vctrs"
      ],
      "Hash": "960e2ae9e09656611e0b8214ad543207"
    },
    "tibble": {
      "Package": "tibble",
      "Version": "3.2.1",
      "Source": "Repository",
      "Repository": "CRAN",
      "Requirements": [
        "R",
        "fansi",
        "lifecycle",
        "magrittr",
        "methods",
        "pillar",
        "pkgconfig",
        "rlang",
        "utils",
        "vctrs"
      ],
      "Hash": "a84e2cc86d07289b3b6f5069df7a004c"
    },
    "tidyr": {
      "Package": "tidyr",
      "Version": "1.3.1",
      "Source": "Repository",
      "Repository": "CRAN",
      "Requirements": [
        "R",
        "cli",
        "cpp11",
        "dplyr",
        "glue",
        "lifecycle",
        "magrittr",
        "purrr",
        "rlang",
        "stringr",
        "tibble",
        "tidyselect",
        "utils",
        "vctrs"
      ],
      "Hash": "915fb7ce036c22a6a33b5a8adb712eb1"
    },
    "tidyselect": {
      "Package": "tidyselect",
      "Version": "1.2.1",
      "Source": "Repository",
      "Repository": "CRAN",
      "Requirements": [
        "R",
        "cli",
        "glue",
        "lifecycle",
        "rlang",
        "vctrs",
        "withr"
      ],
      "Hash": "829f27b9c4919c16b593794a6344d6c0"
    },
    "tinytex": {
      "Package": "tinytex",
      "Version": "0.54",
      "Source": "Repository",
      "Repository": "CRAN",
      "Requirements": [
        "xfun"
      ],
      "Hash": "3ec7e3ddcacc2d34a9046941222bf94d"
    },
    "utf8": {
      "Package": "utf8",
      "Version": "1.2.4",
      "Source": "Repository",
      "Repository": "CRAN",
      "Requirements": [
        "R"
      ],
      "Hash": "62b65c52671e6665f803ff02954446e9"
    },
    "vctrs": {
      "Package": "vctrs",
      "Version": "0.6.5",
      "Source": "Repository",
      "Repository": "RSPM",
      "Requirements": [
        "R",
        "cli",
        "glue",
        "lifecycle",
        "rlang"
      ],
      "Hash": "c03fa420630029418f7e6da3667aac4a"
    },
    "withr": {
      "Package": "withr",
      "Version": "3.0.2",
      "Source": "Repository",
      "Repository": "CRAN",
      "Requirements": [
        "R",
        "grDevices",
        "graphics"
      ],
      "Hash": "cc2d62c76458d425210d1eb1478b30b4"
    },
    "wordcloud2": {
      "Package": "wordcloud2",
      "Version": "0.2.1",
      "Source": "Repository",
      "Repository": "CRAN",
      "Requirements": [
        "R",
        "base64enc",
        "grDevices",
        "graphics",
        "htmlwidgets"
      ],
      "Hash": "10274bd096f5c2ad7471ea0eea0c1424"
    },
    "xfun": {
      "Package": "xfun",
      "Version": "0.49",
      "Source": "Repository",
      "Repository": "RSPM",
      "Requirements": [
        "R",
        "grDevices",
        "stats",
        "tools"
      ],
      "Hash": "8687398773806cfff9401a2feca96298"
    },
    "xml2": {
      "Package": "xml2",
      "Version": "1.3.6",
      "Source": "Repository",
      "Repository": "CRAN",
      "Requirements": [
        "R",
        "cli",
        "methods",
        "rlang"
      ],
      "Hash": "1d0336142f4cd25d8d23cd3ba7a8fb61"
    },
    "xmlparsedata": {
      "Package": "xmlparsedata",
      "Version": "1.0.5",
      "Source": "Repository",
      "Repository": "CRAN",
      "Requirements": [
        "R"
      ],
      "Hash": "45e4bf3c46476896e821fc0a408fb4fc"
    },
    "yaml": {
      "Package": "yaml",
      "Version": "2.3.10",
      "Source": "Repository",
      "Repository": "CRAN",
      "Hash": "51dab85c6c98e50a18d7551e9d49f76c"
    }
  }
}

In summary, we do not recommend to manually change the contents of the files and folders that belong to renv. Rather, the following R functions are good tools to manage your reproducible environments from the console.

8.2.1.2 renv::install

With renv::install, we can install new packages to our project. Assume you need the package palmerpenguins in your project.

Console
renv::install("palmerpenguins")

renv will download the package palmerpenguins. If you want to install packages with dependencies, renv will install these dependencies automatically. In your console you will be asked if you want to install the package to your project library. Type Y in to your console.

Output
# Downloading packages -------------------------------------------------------
- Downloading palmerpenguins from CRAN ...      OK [2.9 Mb in 1.8s]
Successfully downloaded 1 package in 2.1 seconds.

The following package(s) will be installed:
- palmerpenguins [0.1.1]
These packages will be installed into "~/Documents/repro-book/renv/library/macos/R-4.4/aarch64-apple-darwin20".

Do you want to proceed? [Y/n]: 

After that, you should see something in your console similar to this:

Output
# Installing packages --------------------------------------------------------
- Installing palmerpenguins ...                 OK [installed binary and cached in 0.34s]
Successfully installed 1 package in 0.42 seconds.

Now you have installed the package palmerpenguins to your project library.

Some packages require other packages to be loaded. These other packages are called dependencies. Your primary package depends on these other packages to run correctly.

The package psychonetrics has a lot of packages. Install the package to see what happens.

Console
renv::install("psychonetrics")

8.2.1.3 renv::snapshot

When you search in the lockfile for your new installed package palmerpenguins, you will not find it there. renv does not automatically saves the metadata of your installed packages in the lockfile. With renv::snapshot(), we can document the package versions we need in our project. Simply run the command in your Console

Console
renv::snapshot()

In your Console, you will see something like this:

Output
- The lockfile is already up to date.

renv did not add the metadata about palmerpenguins to the lockfile. This is because renv checks if your package is really used somewhere in your project. The bare installation is not enough. This is to not unnecessarily overload the lockfile with packages that are not used in the project. The package has to be used and therefore loaded somewhere in the project. Create a script test_palmerpenguins.R, type library(palmerpenguins), and save it in your project. Then try the snapshot command again:

Console
renv::snapshot()

Your console should have an output like this:

Output
The following package(s) will be updated in the lockfile:

# CRAN -----------------------------------------------
- palmerpenguins    [* -> 0.1.1]

Do you want to proceed? [Y/n]: 

Again, type Y. Then, you should see an output like this:

Output
- Lockfile written to "path/to/your/project/folder/renv.lock".

When you open the lockfile, you will find the metadata of palmerpenguins there. renv::snapshot() is useful because you and your collaborators will be able to reconstruct your package versions. The reconstruction relies on the lockfile and renv::snapshot() will update your current packages used in your project.

8.2.1.4 renv::restore

Say you successfully built up a project library, installed packages to it and saved the metadata into your lockfile. Future you or other collaborators or researchers now want to reproduce your code and need to use the particular package versions. The collaborators found your project and code and downloaded it. They now want to install the particular package versions. To simplify this step, one can use the renv::restore() function.

Console
renv::restore()

Then you should get an output like this:

Output
The following package(s) will be updated:

# CRAN -----------------------------------------------------------------------
- fontawesome    [0.5.2 -> 0.5.3]
- knitr          [1.48 -> 1.49]
- rmarkdown      [2.28 -> 2.29]
- tinytex        [0.53 -> 0.54]
- cyclocomp      [* -> 1.1.1]
- lazyeval       [* -> 0.2.2]
- lintr          [* -> 3.1.2]
- remotes        [* -> 2.5.0]
- rex            [* -> 1.2.1]
- xmlparsedata   [* -> 1.0.5]

Do you want to proceed? [Y/n]:

Type in Y and you should get an output similar to this:

Output
# Downloading packages -------------------------------------------------------
- Querying repositories for available binary packages ... Done!
- Downloading rmarkdown from CRAN ...           OK [2.5 Mb in 1.2s]
- Downloading fontawesome from CRAN ...         OK [1.3 Mb in 0.89s]
- Downloading knitr from CRAN ...               OK [1.1 Mb in 1.1s]
- Downloading tinytex from CRAN ...             OK [140.3 Kb in 0.68s]
Successfully downloaded 4 packages in 6.4 seconds.

# Installing packages --------------------------------------------------------
- Installing fontawesome ...                    OK [installed binary and cached in 0.26s]
- Installing knitr ...                          OK [installed binary and cached in 1.2s]
- Installing tinytex ...                        OK [installed binary and cached in 0.24s]
- Installing rmarkdown ...                      OK [installed binary and cached in 1.6s]
- Installing remotes ...                        OK [linked from cache]
- Installing cyclocomp ...                      OK [linked from cache]
- Installing lazyeval ...                       OK [linked from cache]
- Installing rex ...                            OK [linked from cache]
- Installing xmlparsedata ...                   OK [linked from cache]
- Installing lintr ...                          OK [linked from cache]

The following loaded package(s) have been updated:
- knitr
Restart your R session to use the new versions.

8.2.1.5 renv::status

You can check the status of your dependency management by using renv::status().

Console
renv::status()

If everything is alright, you should get an output message similar to this:

Output
No issues found -- the project is in a consistent state.

However, there can still arise some issues. You can see an example below

Output
The following package(s) are in an inconsistent state:

 package  installed recorded used
 ellipsis y         y        n   

See `?renv::status` for advice on resolving these issues.

Fortunately, the messages displayed by renv are very straightforward. It tells us to go to the helper page by running ?renv::status.

You can just run ?renv::status() in the Console to open the documentation of that function in the Help pane of RStudio. However, the documentation is also available at CRAN when you open the link below. Read the documentation carefully to extract the relevant information that applies to your case.

https://cran.r-project.org/web/packages/renv/renv.pdf#page=56


In the helping page our case is well-described in the section Lockfile vs dependencies(). We can just run renv::snapshot to remove it from the lockfile. Thus, our lockfile does not contain the unused package ellipsis.

Now you got an overview of the most important functions of the package {renv}. The next section will provide you with information on how to use renv in a workflow. However, if you still want to get to know the functions better, we recommend the video in the box below (Tip 8.1) by Rapp (2024).

For further information, see this video to increase your understanding of {renv}.

Video 8.1: “Robust R Code That Will Work Forever With {renv}”. The video by Rapp (2024) aims to display and explain common workflows when creating a reproducible environment using {renv}. License: not specified. Reused without modifications.

8.2.2 renv-workflow

Figure 8.1: “renv workflow” by Kevin Ushey and Hadley Wickham (License: MIT License; reused without modifications)

In Figure 8.1, you can see how the basic functions in renv work. You know the most important things now, but it sure can help to have a guideline.

Step-by-step guide for renv
  1. Create an R project
  2. Install renv \(\rightarrow\) install.packages("renv")
  3. Initialize reproducible environment \(\rightarrow\) renv::init()
  4. Check status \(\rightarrow\) renv::status()
  5. Use help page from renv::status \(\rightarrow\) ?renv::status()
  6. Install packages to project library \(\rightarrow\) renv::install()
  7. Code something that makes you happy, e.g. a wonderful plot
  8. Save your used packages into your lockfile \(\rightarrow\) renv::snapshot()
  1. Download the project folder e.g. from https://osf.io or https://zenodo.org
  2. Open R project by clicking the .Rproj file
  3. Check status \(\rightarrow\) renv::status()
  4. Use help page from renv::status \(\rightarrow\) ?renv::status()
  5. Restore the project library from the lockfile \(\rightarrow\) renv::restore()
  6. Run the code written be past you or an other researcher

8.3 Limitations of renv

As you can see in the lockfile, renv tracks not only the package versions but also the R version. However, renv cannot solve reproducibility issues when it comes to different R versions. It is possible to deal with this problem installing the specific R version used in the project you want to reproduce. Another way is using docker. However, it requires more time and work to make a project reproducible. Further, the benefits of separate projects comes with a constraint. Possible bug fixes that are included in later versions of a package are not implemented in the project libraries. Nevertheless, we recommend renv as a valuable tool for increasing a project’s reproducibility.

8.4 References

We would like to express our gratitude to the following resources which have been essential in shaping this chapter. We recommend these references for further reading and watching.

Authors Title Website License Source
Rapp (2024) Robust R Code that will work forever with {renv} Not specified
Ushey and Wickham (2024) renv: Project Environments MIT