Restore renv lock file without redownloading packages

I am using renv within a docker container.

I've used renv::isolate() to make a self contained library. To save time and avoid re-downloding and re-building all packages I've tried doing the following in my Dockerfile

# Restore R packages
# Copy renv.lock file
COPY renv.lock /tmp/renv.lock
# Change working directory
WORKDIR /root/project/
# Copy renv directory with project library
COPY ./renv .
# Restore from renv.lock using binaries in the renv library
RUN R -e "renv::restore(lockfile='/tmp/renv.lock', library='/root/project/renv/library/R-4.0/x86_64-pc-linux-gnu')"

Unfortunately, renv still tries to re-download and re-install each package instead of using the library copied into /root/project/renv/

How can I avoid re-downloading and re-building the packages?

I found this reference to setting custom paths.

Not sure if the key is in there or not.

Of tangential interest, renv::isolate() does not seem to copy files in the python\conda environment from the cache to the project library. I'm using renv 0.13.2. The R packages all get copied over to the project library but the python files are still soft linked to the cache.

Just a bump ... wondering if anyone has thoughts on how to avoid re-download and rebuild on packages when binaries are available.

This is surprising to me. Are you certain that your pre-existing packages are indeed installed and available in this library path?


The other potential option would be to place binary package tarballs in the project's renv/local folder -- see Installing from Local Sources • renv for more details.

The other potential solution here would be to use RSPM, as that will be able to serve binary copies of packages on Linux -- you'd just need to configure renv / your Dockerfile to use the appropriate repository.

@kevinushey Thanks for getting back to me ...

So very embarrassing but but my renv folder was being copied to the wrong location in the Dockerfile. It was being copied to /renv/ instead of /root/project/renv.

Now the Dockerfile build doesn't try to re-download and re-build all the packages when doing
RUN R -e "renv::restore(lockfile='/tmp/renv.lock', library='/root/project/renv/library/R-4.0/x86_64-pc-linux-gnu')"

However, R still does not appear to recognize the library as I can't library() any of the packages included in '/root/project/renv/library/R-4.0/x86_64-pc-linux-gnu

I tried setting various environment variables with

ENV RENV_PATHS_ROOT=/root/project/renv
ENV RENV_PATHS_LIBRARY=/root/project/renv/library
RUN echo "RENV_PATHS_ROOT=${RENV_PATHS_ROOT}" >> ${R_HOME}/etc/Renviron

but it doesn't seem to help.

Entering the container, running R, and running
renv::restore(lockfile='/tmp/renv.lock', library='/root/project/renv/library/R-4.0/x86_64-pc-linux-gnu')
The library is already synchronized with the lockfile.

but something like
Error in library("Seurat") : there is no package called ‘Seurat’

What do you have for .libPaths?


[1] "/usr/local/lib/R/site-library" "/usr/lib/R/site-library"
[3] "/usr/lib/R/library"

Interesting, I would have thought renv::restore() would have configured the .libPaths() correctly.

.libPaths( c( .libPaths(), "/root/project/renv/library/R-4.0/x86_64-pc-linux-gnu/") )

seems to allow me to library() most of the packages in /root/project/renv/library/R-4.0/x86_64-pc-linux-gnu/

What's the preferred way to set .libPaths() during initialization of R?

Also, I'm getting an error in the primary package I'm trying to run

Error: package or namespace load failed for ‘Seurat’ in dyn.load(file, DLLpath = DLLpath, ...):
 unable to load shared object '/root/project/renv/library/R-4.0/x86_64-pc-linux-gnu/stringi/libs/': cannot open shared object file: No such file or directory

It was running fine from the cache before I did isolate() and copied the library to the docker container.

If you haven't already seen it, Using renv with Docker • renv may be helpful.

You likely need to install the requisite system library (libicu) on your container. Or, if you did install that library, then the issue is most likely that the version used in your container differs from your host machine.

renv::restore() doesn't change the library paths; it only installs packages from a lockfile into the requested library paths. Changing the active library paths for the session is a separate step.

Thanks to everyone ... I seem to have this working now.

Biggest issues were :

  • library copied into wrong location in container
  • library not included in .libPath
  • system libraries not installed
  • installing libicu-dev not recognized by stringi - reinstalled with install.packages('stringi') as workaround

Here's my final Dockerfile