R Environments

R Environments#

Author: Amy Heather (GitHub: amyheather, ORCID: 0000-0002-6596-3479).

Reviewer: Tom Monks (GitHub: TomMonks, ORCID: 0000-0003-2631-4481).

Adapted from: DES RAP Book: Reproducible Discrete-Event Simulation in Python and R (Heather et al., 2025). This is a free online book which explains how to develop reproducible simulation studies as part of a reproducible analytical pipeline, using practical examples and open-source code. While it focuses on discrete-event simulation, many of its principles and techniques apply broadly across different types of projects. It was developed as part of the project STARS: Sharing Tools and Artefacts for Reproducible Simulations. It is supported by the Medical Research Council [grant number MR/Z503915/1].

License: Creative Commons Attribution-ShareAlike 4.0 International license (CC BY-SA 4.0).

Course objectives#

This short course will guide you through the essentials of managing R environments.

  • 🌎 Environments: What R environments are and why they matter.

  • 🔄 R version: Switching between versions of R.

  • 📦 Packages: Dependency management using renv.

  • ⚙️ Other: Handling system libraries and project settings.

  • 🛠️ Recreate & troubleshoot: Restoring environments and common fixes.

  • 🧪 Activities: Have a go at R environment management!

  • 📚 Further ideas: Advanced tools and workflows for managing R environments.


🌎 Environments

What is an R environment?

An R environment is the complete computational context required to run an R project. It includes:

  • The version of R itself.

  • All R packages (and their versions) used in your analysis.

  • System libraries required by some R packages.

  • Project-specific settings (e.g., .Rproj, .Rprofile).

Why are R environments important?

  • Reproducibility: By recording the exact R version and package versions, you can recreate your analysis at any time, on any machine, and get the same results.

  • 🏝️ Isolation: Each project can have its own set of packages and R version, preventing conflicts between projects.

  • 🤝 Collaboration: Ensures that everyone working on the project uses the same setup.


🔄 R version

For most users, the best way to manage R versions is to use rig. It is a tool that allows you to easily install, list and switch between R versions on Windows, Mac and Linux.

How to use rig

Install rig

Follow the installation instructions for your operating system on the rig GitHub page. After installation, check that it works by running:

rig --version

View available R versions

List all R versions installed on your machine:

rig list

Example output:

* name   version  aliases
------------------------------------------
  3.6.0           
  4.2.2           
  4.3.1           
  4.4.1           
  4.5.0  

Add a new R version

To install a specific R version:

rig add 4.1.2

Or simply add the latest version:

rig add

Set the active R version

Choose which R version should be active (for example, when you open RStudio):

rig default 4.1.2

This makes the selected version the default for new R sessions. (Note: If you later change versions manually or with other tools, you may need to reset this.)

Legacy methods

If you need to know about older or alternative approaches, here are some legacy methods:

  • Mac: RSwitch, Homebrew

  • Windows: CRAN installer

  • Linux: Manual installation, symbolic links

Note: These methods can be inconsistent and are generally more complex than rig.

📦 Packages

Tools for dependency management

The processing of tracking and controlling the packages your project uses, including their versions, is called dependency management.

In R, the most popular tool for managing dependencies is renv, which is covered in this course. renv replaced and improved upon the previous tool, Packrat.

Note: There is a new tool currently in development called rv which aims to provide a more modern, declarative workflow. It requires all dependencies to be specified before installation (rather than taking snapshots as you go along like renv).

Creating an renv environment

View steps

1. Install renv

If you haven’t already, install renv from CRAN:

install.packages("renv")

2. Create an R project

It’s best to use renv within an R project. R projects are commonly created and managed by RStudio.

In RStudio, select “File > New Project…” and choose “Existing Directory”.

Screenshot from New Project Wizard: Create Project screen

Navigate to your project directory, then select “Create Project”.

Screenshot from New Project Wizard: Create Project from Existing Directory screen

This will create :

  • .Rproj: project file (contains some settings for the project).

  • .Rproject.user/: hidden folder with temporary project files (e.g. auto-saved source documents).

If you are not using RStudio, R projects can be difficult to set-up, as they have to be created manually. It is possible to use renv without an R project though, as discussed in this GitHub issue. This can be done using setwd() to set your repository as the current working directory, and then continuing with the steps below.

3. Initialise renv

In your R console, run:

renv::init()

This creates:

  • renv/: stores packages for the project.

  • renv.lock: records packages and the exact versions used.

  • .Rprofile: ensures renv activates when the project opens.

Example renv.lock containing only renv:

{
  "R": {
    "Version": "4.4.1",
    "Repositories": [
      {
        "Name": "CRAN",
        "URL": "https://packagemanager.posit.co/cran/latest"
      }
    ]
  },
  "Packages": {
    "renv": {
      "Package": "renv",
      "Version": "1.0.7",
      "Source": "Repository",
      "Repository": "CRAN",
      "Requirements": [
        "utils"
      ],
      "Hash": "397b7b2a265bc5a7a06852524dabae20"
    }
  }
}

When you initialise renv, you project gets its own project library - a private folder (renv/library/) where packages are installed just for this project. This means package versions are isolated and recorded for each project, so updating a package in one project won’t break others. This makes collaboration and reproducibility much easier.

This is different from the user library, which is the default shared location where R installs packages used by all your R projects. See the “Packages” section on RStudio, which will show your project v.s. user library:

Screenshot of RStudio within renv::init() in empty directory, creating project library alongside user library

Some further information relevant when initialising renv:

Implicit or explicit mode

If a DESCRIPTION file is present, renv will prompt you to choose how dependencies are discovered:

  • Implicit mode: renv will scan you project files for any packages used in your code.

  • Explicit mode: renv will use only the packages listed in your DESCRIPTION file.

We recommend choosing implicit mode for most projects, as it ensures that all packages actually used in your code are detected and managed, even if you forget to list them in DESCRIPTION.

We’ll explain more about DESCRIPTION files and these modes in the section on adding packages to the environment.

Initialising a bare environment

By default, renv::init() will scan and install packages into your project library. If your directory is empty or contains no code using packages, only renv itself will be installed.

If you want to initialise renv without installing any packages, you can use:

renv::init(bare = TRUE)

This will create renv/ and .Rprofile but not renv.lock or a project library.

However, when you later run renv::snapshot(), renv will scan and install packages at that point. If you use implicit mode, it will detect and install all packages used in your code - even if you started with a bare environment.

We’ll explain more about snapshots and implicit mode in the section on adding packages to the environment.

Adding packages to the renv environment

View steps

It is possible to simply install packages directly using commands like:

renv::install("packagename")
install.packages("packagename")

However, we recommend using a DESCRIPTION file. This is a file listing only the main packages your project directly depends on - i.e. those you might have add using renv::install().

This differs from renv.lock which records all packages needed to recreate your environment, including every main package and all their dependencies, plus the exact versions used.

The benefit of using a DESCRIPTION file when adding packages is:

  • 📝 Clear requirements. The DESCRIPTION file gives a simple, readable summary of your project’s main packages. It’s much easier to read than renv.lock.

  • 📦 Consistency with package development. If your project is (or might become) an R package, the DESCRIPTION file is the standard way to declare dependencies.

  • 🔄 Alternative for environment recreation. While renv.lock is the primary tool for restoring an renv environment, having a DESCRIPTION file is a valuable backup. If you encounter issues with renv.lock, you can use DESCRIPTION to reinstall the main dependencies.

  • 🎯 Explicit snapshots. If you want precise control over what’s included in renv.lock, you can use an “explicit” snapshot. This means only the packages listed in DESCRIPTION (and their dependencies) are recorded.

1. Create a DESCRIPTION file

Create a file named DESCRIPTION and use the following template (which can be generated instead using usethis::use_description()):

Package: packagename
Title: What the Package Does (One Line, Title Case)
Version: 0.0.0.9000
Authors@R: 
    person("First", "Last", , "first.last@example.com", role = c("aut", "cre"))
Description: What the package does (one paragraph).
License: `use_mit_license()`, `use_gpl3_license()` or friends to pick a
    license
Encoding: UTF-8
Roxygen: list(markdown = TRUE)
RoxygenNote: 7.0.0

2. List dependencies

Dependencies can be listed as:

  • Imports (required packages).

  • Suggests` (optional/development packages).

For non-package projects, it’s simplest to list all dependencies under Imports, which will be identified by renv (whilst those under Suggests may not unless used in scripts).

Suggests is more relevant when constructing a package, as it distinguishes packages necessary only for optional features, vignettes or testing, from those required within the package itself.

Note: In the R Packages book, they recommend that - in DESCRIPTION - no versions are specified, or a minimum version is specified if you know that an older version of specific package/s would break the code. This is why it is important to also create an renv.lock file (as below), so you do have a record of the exact versions used.

Example DESCRIPTION with packages dplyr and future:

Package: example
Title: Example DESCRIPTION
Version: 0.0.0.9000
Authors@R: 
    person("Amy", "Heather", , "a.heather2@exeter.ac.uk", role = c("aut", "cre"))
Description: This is an example DESCRIPTION, used for environment management.
License: MIT + file LICENSE
Encoding: UTF-8
Roxygen: list(markdown = TRUE)
RoxygenNote: 7.0.0
Imports:
    dplyr
    future

3. Install packages from DESCRIPTION

Install packages listed in DESCRIPTION (and their dependencies) with:

renv::install()

4. Update renv.lock

Take a snapshot of your environment and update renv.lock:

renv::snapshot()

There are three snapshot types:

  • Implicit (default): Records packages in DESCRIPTION and those used in your code.

  • Explicit: Only records packages listed in DESCRIPTION.

  • All: Records all packages in your environment.

We recommend using the default (implicit) to ensure all used packages are captured, even if not listed in DESCRIPTION. However, you should remove unused scripts to avoid capturing unnecessary packages.

To check your current snapshot type:

renv::settings$snapshot.type()

To change it if needed:

renv::settings$snapshot.type("implicit")
renv::settings$snapshot.type("explicit")
renv::settings$snapshot.type("all")

Deleting an renv environment

View steps

To remove renv from a project, run:

renv::deactivate(clean = TRUE)

This will remove the renv auto-loaded, the renv/ directory, and the renv.lock file in one step, and restart the R session.

⚙️ Other

Besides the packages and R version used, your R environment will also include system libraries (external software required by some packages) and project-specific settings (e.g. .Rproj, .Rprofile).

Most researchers handle these components by:

  • Documenting required system libraries in the project’s README or set-up instructions.

  • Including project files (like .Rproj and .Rprofile) in version control (e.g., Git).

🛠️ Recreate & troubleshoot

Recreating an existing R environment

View steps

This flowchart guides you through the main choices you’ll face when rebuilding an R environment:

Summary workflow for recreating an R environment for an existing project

Some of the essential actions from this flowchart - alongside some additional considerations - are described below.

Switch R version.

  • Use rig to easily change to the required R version (see ‘🔄 R version’).

Restore packages.

  • If you have an renv.lock file, run: renv::restore().

  • If you are using a DESCRIPTION file, run: renv::install().

Snapshot mode.

  • In ‘📦 Packages’, we recommend ‘implicit’ mode so that renv.lock captures all packages used, even if you have forgot to add them to DESCRIPTION. However, when rebuilding an environment, ‘explicit’ mode can help ensure all required packages are listed in DESCRIPTION.

Additional environment components.

  • System libraries - covered in troubleshooting section.

  • Project-specific settings - these files (e.g. .Rprofile, .Rproj) should be copied over if provided. They are not typically a source of errors but important for restoring full project environment, as they may contain custom project options.

Troubleshooting

View steps

Restoring an R environment can often run into issues, especially with older projects or system differences. Below are common problems and solutions.

Unavailable packages

When recreating environments with older R versions or package versions, you may encounter errors if those packages are no longer available for your chosen R version. CRAN often archives older packages, and support for very old R versions is limited.

Symptoms:

  • Errors stating that a package or a specific version cannot be found or installed.

  • Installation fails even though the package exists for newer R versions.

Solutions:

  • If exact reproducibility isn’t critical, update to a more recent R version and/or newer package versions.

  • For legacy work, search for archived source tarballs or consult the CRAN archive, but success isn’t guaranteed.

Backdating

If you set up your environment with the latest R and package versions (for example, when no specific versions are listed), you may find your code requires older package versions to work as expected.

Symptoms:

  • Code relies on functions or behaviors from earlier package versions.

  • Latest package versions introduce breaking changes.

Solutions:

  • Specify minimum or exact versions in your DESCRIPTION file.

  • Be aware that not all old versions are available for every R version; you may need to adjust your R version or accept a newer package.

To specify a minimum version in DESCRIPTION:

Imports:
    dplyr (>= 1.0.0)

To install a particular version using renv (which is then captured in renv.lock by calling renv::snapshot()):

renv::install("dplyr@1.1.2")

Missing system dependencies

Some R packages require external system libraries (e.g., C libraries, database clients) not installed by default.

Symptoms:

  • Package installation fails with errors about missing libraries (e.g., “cannot find -lssl”, “libcurl not found”, missing .so files).

  • Consult the CRAN page for each package (OR SPECIFIED ONE IN ERROR?); most list system requirements. As an example, the openssl and curl packages commonly require system libraries. See this GitHub issue for a real-world case and solution.

Solutions:

  • Check the CRAN page for each package for system requirements. The openssl and curl packages are a common source of these issues.

  • Install the required system dependencies and document them in your README for others. For example:

    • Ubuntu/Debian: sudo apt-get install libssl-dev libcurl4-openssl-dev.

    • Fedora/RHEL: sudo dnf install openssl-devel libcurl-devel.

    • MacOS: brew install openssl curl.

    • Windows: Follow package documentation or use precompiled binaries.

Legacy user libraries

On systems where R has been installed for a long time, the user library (the default location for installed packages) may contain outdated or conflicting packages. This can interfere with renv, sometimes causing it to fail silently or behave unpredictably.

Symptoms:

  • renv commands have no effect or fail with unclear messages.

  • Packages are loaded from the user library instead of the project library.

Solutions:

  • Check .libPaths() to confirm the project library is listed first when renv is active.

  • Temporarily move or rename your user library directory and restart R to see if renv works correctly.

  • If issues persist, consider reinstalling R or resetting your user library.

  • As a last resort, a clean operating system install can resolve deep or persistent conflicts.

General tips

Update renv: Bugs are fixed regularly - ensure you’re using the latest version.

Check permissions: Make sure you have write access to your project directory.

Consult logs: Use renv::diagnostics() to generate a report on your environment.

Search for known issues: Many problems are discussed (and solved) in the renv GitHub Issues tracker.

🧪 Activities

Let’s put theory into practice! These activities are designed to help you experience real-world workflows for managing R environments using renv and rig.

Activity 1: Create a reproducible R project from scratch

Goal: Set up a new R project with renv, add a package, capture the environment for reproducibility, and share it with others.

Suggested package and script: Use the ggplot2 package, and create a script named plot_example.R with the following code:

library(ggplot2)
ggplot(mtcars, aes(mpg, wt)) + geom_point()
View solution
  1. Create a new R project.

    • In RStudio: Go to “File” > “New Project…” and choose “New Directory” or “Existing Directory” as needed.

  2. Initialize renv.

    • In the R console, run:

      install.packages("renv")
      renv::init()
      
  3. Install a package.

    • For example, to add ggplot2, add this to a DESCRIPTION file and then run

      renv::install()
      
  4. Write and run a simple script.

    • Create a new R script (e.g., plot_example.R) with:

      library(ggplot2)
      ggplot(mtcars, aes(mpg, wt)) + geom_point()
      
    • Run the script to confirm everything works.

  5. Snapshot the environment.

    • Save the current state of your environment:

      renv::snapshot()
      
    • This updates the renv.lock file, recording all package versions.

  6. Share your project.

    • Your project folder now contains everything needed for someone else to reproduce your analysis - just share the folder (via GitHub, ZIP, etc.).

Review the 📦 Packages page for more information on these steps.

Activity 2: Reproduce an existing R project

Goal: Clone a repository with a pre-configured renv environment, switch to the correct R version, restore dependencies, and run a basic R script.

Repository: amyheather/renv-reproduce-activity

View solution
  1. Clone the provided repository.

    • git clone https://github.com/amyheather/renv-reproduce-activity.git

    • cd renv-reproduce-activity

  2. Switch to the required R version.

    • Check the renv.lock file or README for the required R version.

    • Use rig (or your preferred tool) to switch R versions.

  3. Restore the project environment.

    • Open the project in RStudio.

    • Run renv::restore().

  4. Run the example code.

    • Locate and run the provided R script (analysis.R).

  5. Troubleshoot (if needed).

    • If you encounter errors, refer to the troubleshooting section in 🛠️ Recreate & troubleshoot.

📚 Further ideas

If you are interested in exploring more advanced or alternative approaches to managing reproducible R environments - especially when dealing with complex external dependencies - consider the following tools and resources:

Docker for R

Using Docker allows you to encapsulate your entire R environment, including system libraries, R versions, and packages, inside a container. This approach can solve many issues related to external dependencies and ensures that your analysis runs identically across different systems.

  • dockerfiler: An R package for programmatically creating Dockerfiles, making it easier to build reproducible R environments with custom dependencies.

  • rocker: A collection of Docker images for R, maintained by the R community, which you can use as a base for your own projects.

R-universe

R-universe is an online platform for building, hosting, and distributing R packages—including those not available on CRAN. It can help you:

  • Access packages from multiple sources, not just CRAN.

  • Set up custom repositories (collections of R packages) for your team or organisation.

  • Centralise package management (as repositories can include public, private and experimental).