R's dependency management has evolved from basic built-in tools to modern solutions that provide reproducibility and isolation.
R includes basic package management functionality:
# Install packages
install.packages("dplyr")
install.packages(c("ggplot2", "tidyr"))
# Load packages
library(dplyr)
require(ggplot2) # Similar but returns FALSE if not available
# Update packages
update.packages()
# Remove packages
remove.packages("dplyr")- CRAN: Comprehensive R Archive Network (primary repository)
- Bioconductor: Bioinformatics packages
- GitHub: Development versions and custom packages
# From CRAN (default)
install.packages("dplyr")
# From Bioconductor
BiocManager::install("DESeq2")
# From GitHub
devtools::install_github("tidyverse/dplyr")For R packages, the DESCRIPTION file specifies dependencies:
Package: mypackage
Version: 0.1.0
Imports:
dplyr (>= 1.0.0),
ggplot2
Suggests:
testthat,
knitr
Depends:
R (>= 4.0.0)
- Imports: Packages needed for your package to work
- Suggests: Optional packages (for vignettes, tests, etc.)
- Depends: Packages attached when yours is loaded
- LinkingTo: For C++ dependencies
dplyr (>= 1.0.0) # Minimum version
ggplot2 (>= 3.0, < 4.0) # Version range
tidyr (== 1.2.0) # Exact version (rare)
The modern standard for project-level dependency management:
# Initialize renv for a project
renv::init()
# Install packages (tracked automatically)
install.packages("dplyr")
# Save the current state
renv::snapshot()
# Restore from lockfile
renv::restore()
# Update packages
renv::update()Project Structure:
myproject/
├── renv.lock # Lockfile with exact versions
├── renv/ # Project library
│ └── library/ # Installed packages
├── .Rprofile # Auto-activates renv
└── renv/activate.R # Activation script
renv.lock example:
{
"R": {
"Version": "4.2.0",
"Repositories": [
{
"Name": "CRAN",
"URL": "https://cran.rstudio.com"
}
]
},
"Packages": {
"dplyr": {
"Package": "dplyr",
"Version": "1.0.9",
"Source": "Repository",
"Repository": "CRAN"
}
}
}Key Features:
- Project-specific libraries (isolated environments)
- Reproducible with
renv.lock - Caches packages globally to save space
- Integrates with RStudio
The predecessor to renv, now superseded:
packrat::init()
packrat::snapshot()
packrat::restore()Note: Use renv instead for new projects.
Uses MRAN (Microsoft R Archive Network) time-based snapshots:
library(checkpoint)
checkpoint("2023-01-15") # Use packages as of this dateStatus: MRAN was deprecated in 2022; limited usefulness now.
R's built-in install.packages():
- Automatically installs dependencies listed in
ImportsandDepends - Uses the latest compatible versions from repositories
- No sophisticated version conflict resolution
# Check for issues
renv::diagnostics()
# See dependency tree
renv::dependencies()R has multiple library paths:
.libPaths() # View library locations
# [1] "~/R/library" # User library
# [2] "/usr/lib/R/library" # System libraryWithout renv:
- Packages installed globally
- All projects share same package versions
- Can lead to conflicts
With renv:
- Each project has its own library
- Different projects can use different package versions
- Isolated from system library
For developing packages:
library(devtools)
# Load your package for development
load_all()
# Install dependencies from DESCRIPTION
install_deps()
# Check package
check()
# Install your package
install()#' @importFrom dplyr filter mutate
#' @import ggplot2These tags in your documentation generate the DESCRIPTION file dependencies.
For ultimate reproducibility:
FROM rocker/r-ver:4.2.0
RUN R -e "install.packages('renv')"
COPY renv.lock renv.lock
RUN R -e "renv::restore()"The rocker project provides versioned R Docker images.
- Use renv for projects: Ensures reproducibility and isolation
- Commit renv.lock: Version control your lockfile, not
renv/library/ - Specify minimum versions: In
DESCRIPTIONfiles for packages - Regular snapshots: Run
renv::snapshot()after package changes - Use
.Rprofile: renv creates this to auto-activate - Document session info: Use
sessionInfo()to record your environment
# Save session information
writeLines(capture.output(sessionInfo()), "session_info.txt")# Create project directory
dir.create("myproject")
setwd("myproject")
# Initialize renv
renv::init()
# Install packages
install.packages("tidyverse")
# Save state
renv::snapshot()# Team member clones repo
git clone repo_url
cd repo
# Open R in project
# renv activates automatically
# Install exact versions
renv::restore()# Update a package
install.packages("dplyr")
# Record the update
renv::snapshot()
# If issues arise, rollback
renv::restore()Key Differences from Python/Julia:
- R's built-in dependency management is simpler but less sophisticated
- renv is the modern solution (similar to Python's Poetry or Julia's Pkg)
- No built-in semantic versioning or complex resolution
- Heavy reliance on CRAN's stable package ecosystem
- Environment isolation was an afterthought, not built-in from the start