Great Scott!

A Chronicle of the Dangers of Time Traveling in R

  1. Unstable Equilibrium
  2. The Diagonal
  3. The Tale of Lemon Lucifer
  4. The Time Traveler’s Handbook
  5. An Elegy for Cassini

Unstable Equilibrium

renv workflow

  1. Create a project
  2. renv::init()
  3. Write code, install packages
  4. renv::snapshot()
  5. Iterate

Restoring project states

  1. Clone and open project
  2. renv::restore()

uv workflow

  1. Create a project
  2. uv init
  3. Write code, uv add <python package>
  4. uv run script.py
  5. Iterate

Restoring project states

  1. Clone and open project
  2. uv sync

The Diagonal

R works great today….

…but entropy comes for us all

Package states

  • Package developers write in source code, then bundle the code to send to CRAN.
  • CRAN builds binaries or otherwise supplies the bundle to install.
  • We install the result with install.packages() and friends.
  • We bring an installed package into memory with library().

Package repositories

getOption("repos")
                       CRAN 
"https://cran.rstudio.com/" 
attr(,"IDE")
[1] TRUE
  • CRAN offers binaries for Windows and Mac, typically for the latest version and the version before that
  • CRAN archives package bundles for all versions that have been on CRAN, but these then need to be built from source

Package repositories

install.packages(
  "data.table",
  repos = c(CRAN = "https://packagemanager.posit.co/cran/2026-02-13")
)

Convincing renv to use a repo

.Rprofile
options(c(CRAN = "https://packagemanager.posit.co/cran/2026-02-13"))

renv::checkout(repo = ...)

  • You can change the repository your packages are installed from via renv::checkout()

renv::checkout(date = "yyyy-mm-dd")

  • renv::checkout() also has a fast way to checkout from Posit Package Manager’s daily CRAN snapshots

rig: The R Installation Manager

  • rig is a command line tool that you use in the terminal (not the R console) to manage R installations
  • rig add <version>, e.g. rig add 4.1.0 rig add release
  • rig default <version>, rig rstudio <version>
  • You can also look up the date an R version was released with rversions::r_versions() to figure out which R version was the release version on a given date

R works great on a given day

The Tale of Lemon Lucifer

renv

ℹ Using R 4.5.2 (lockfile was generated with R 4.4.1)
rig add 4.4.1
rig default 4.4-arm64

renv

renv::restore()
...
Error:
failed to find binary for 'cmdstanr 0.8.1' in package repositories

renv

The README says to use:

install.packages("cmdstanr", repos = c("https://stan-dev.r-universe.dev", "https://packagemanager.posit.co/cran/latest"))

Then ignore cmdstanr:

renv::restore(exclude = "cmdstanr")

Success!!

rv workflow

  1. Create a project
  2. rv init
  3. Write code, rv add <R package>
  4. rv run script.R or work directly in R
  5. Iterate

Restoring project states

  1. Clone and open project
  2. rv sync

rv

rv configure repository replace CRAN --url "https://packagemanager.posit.co/cran/2025-03-15"
rv migrate renv

rv

rv configure repository add multiverse --url https://production.r-multiverse.org/2026-03-15
rv add cmdstanr --repository multiverse
rv sync

Success!

Running the project

targets::tar_make()
...
LaTeX Error: File `tblrlibrotating.sty' not found.

Case 38: A Buffalo Passes the Window

Goso said, “A buffalo passes through a window. His head, horns, and four legs all go past. But why can’t the tail pass too?”

docker

Pinning cmdstanr:

RUN R -e 'cmdstanr::install_cmdstan(dir = "/home/rstudio/.cmdstan", cpp_options = list("CXX" = "clang++"), version = "2.36.0")'

Pinning latex:

RUN Rscript -e 'tinytex::install_tinytex(version = "2025.02")'

...

RUN tlmgr repository set https://ftp.math.utah.edu/pub/tex/historic/systems/texlive/2024/tlnet-final

The Time Traveler’s Handbook

Do not split yourself across time

  1. Pick a day
  2. Identify a source of binaries and the R version for that day
  3. Sync your packages and R version to that day
  4. Move forward in time all at once

renv

  • For new projects, use options(repos = "..."). Check your lock file to make sure renv is playing along.
  • For existing projects, renv::checkout(date = "..."). In my experience, you may need to manually change repos in the lock file.

rv

  • For new projects: rv configure repository
  • For existing projects: rv migrate renv

rig

  • Going back in time: rversions::r_versions(): rig add <version>, rig default <version_name>
  • Going forward in time: use rig add release and rig default release to update to today’s released version

Containers together with package managers

  • Using a specific day with a source of binaries makes it substantially easier to restore environments in containers
  • Containers extend the reproducibility half-life of a project
  • Do not split your container across time, either

An Elegy for Cassini

Project end-of-life

  • Without maintenance, the renv option of lemon-lucifer has reached end-of-life.
  • Are you willing to maintain your project? For how long?
  • Do other people know if a project is active, in maintenance, or crashing into Saturn?

Thank you!