R packages

ID

cran

Links

Home page · Documentation · Repository · Wikipedia

Platforms

🅱️ BSD · 🐧 Linux · 🍎 macOS · ⨂ Unix · 🪟 Windows

Operations

installed · outdated · search · install · upgrade · upgrade_all · remove

purl types

pkg:cran/

CLI name

Rscript

Every call

Rscript --no-init-file <command>

Issues and PRs

📦 manager: cran

Source

cran.toml

R’s own package management, the install.packages() family of its utils package, driven headlessly through Rscript (https://www.r-project.org).

A package is a name from the repositories R is configured with, CRAN by default, and every verb takes that name. Each operation is one Rscript -e call, so the listings print a format chosen here. The package name reaches the code as a trailing argument, which R reads with commandArgs().

The inventory holds the packages of the libraries the user can write to. A fresh account has none, so the first install creates the personal library that R_LIBS_USER names, as an interactive R session offers to. A library the user cannot write to is left out, like /usr/lib/R/site-library where the r-cran-* packages of Debian go, and so are the base packages of R itself.

Parsing notes, verified against R 4.5.2 on Ubuntu 26.04:

  • --no-init-file skips ~/.Rprofile and the .Rprofile of the working directory, which R reads first. The profile of an renv project would otherwise swap the library, and anything a profile prints would land in the output being parsed. The site profile still applies, and with it the CRAN mirror a distribution sets. Without one, <https://cloud.r-project.org> is used.

  • install.packages() only warns, and exits 0, for a package it cannot find (“package ‘x’ is not available for this version of R”), and so does available.packages() for a repository it cannot reach. Every call runs with options(warn = 2), which turns such a warning into an error.

What mpm adds to cran

Through mpm, cran gains --exact and --extended search, to narrow to exact names or match descriptions.

Bigger still, mpm reaches across every manager at once: mpm installed and mpm outdated cover cran alongside every other manager you run in one table, mpm upgrade --all updates them together, and mpm sbom exports the whole machine as one bill of materials.

Every mpm command also gains --dry-run and --plan previews, cross-scheme version comparison and purl identifiers. See manager augmentations for how each one is built.

Your cran commands, in mpm

You already know cran: each operation maps one-to-one onto mpm, in an interface shared by every manager.

To…

With cran

With mpm

List what’s installed

`Rscript -e options(warn = 2L); r <- getOption(“repos”); if (is.na(r[“CRAN”])

List outdated packages

`Rscript -e options(warn = 2L); r <- getOption(“repos”); if (is.na(r[“CRAN”])

Search for a package

`Rscript -e options(warn = 2L); r <- getOption(“repos”); if (is.na(r[“CRAN”])

Install a package

`Rscript -e options(warn = 2L); r <- getOption(“repos”); if (is.na(r[“CRAN”])

Upgrade one package

`Rscript -e options(warn = 2L); r <- getOption(“repos”); if (is.na(r[“CRAN”])

Upgrade everything

`Rscript -e options(warn = 2L); r <- getOption(“repos”); if (is.na(r[“CRAN”])

Remove a package

`Rscript -e options(warn = 2L); r <- getOption(“repos”); if (is.na(r[“CRAN”])

Prefix any command above with --dry-run to simulate the underlying manager calls without touching the system: the safe way to watch what mpm would do before trusting it.

Operations

Operation

Supported

Notes

installed

✅

outdated

✅

orphans

search

✅

Matches package names only: the repository index carries no description. Exact and extended search backfilled by mpm.

install

✅

upgrade

✅

upgrade_all

✅

remove

✅

sync

❌

Each operation reads the repository index online, so nothing needs a refresh.

cleanup

doctor

Configuration

  • Ignore cran on the mpm CLI by passing the --no-cran option.

  • Ignore it for every run in your configuration:

    [mpm]
    cran = false
    
  • Raise the timeout of all cran calls:

    [mpm.overrides.cran]
    timeout = 900
    
  • Run mpm config-template cran to print all overridable settings for your configuration file:

    [mpm.overrides.cran]
    cli_names = [
        "Rscript",
    ]
    cli_search_path = []
    dry_run = false
    plan = false
    post_args = []
    pre_args = [
        "--no-init-file",
    ]
    pre_cmds = []
    stop_on_error = false
    unmaintained = false
    version_cli_options = [
        "--version",
    ]
    version_regexes = [
        "version\\s+(?P<version>\\d+\\.\\d+\\.\\d+)",
    ]
    
    [mpm.overrides.cran.operations.install]
    extra_args = []
    
    [mpm.overrides.cran.operations.installed]
    extra_args = []
    
    [mpm.overrides.cran.operations.outdated]
    extra_args = []
    
    [mpm.overrides.cran.operations.remove]
    extra_args = []
    
    [mpm.overrides.cran.operations.search]
    extra_args = []
    
    [mpm.overrides.cran.operations.upgrade_all]
    extra_args = []
    
    [mpm.overrides.cran.operations.upgrade_one]
    extra_args = []
    

The arguments and environment variables listed in the box atop this page are forced on every cran call, so runs stay quiet, non-interactive and reproducible: the defaults you would set in CI anyway.

Recipes

A few jobs you would otherwise script around cran, one mpm command each:

  • Snapshot and clone a machine: mpm --cran dump cran.toml, then mpm restore cran.toml on the next one.

  • Export a compliance SBOM: mpm --cran sbom (CycloneDX by default, --spdx for SPDX).

Privilege escalation

mpm runs this manager as the current user and never prepends sudo by default. Flip the policy for its privileged operations with --sudo or the per-manager sudo override.

None of its operations is privileged.

See privilege escalation for the full policy.

Cooldown

State of R packages’s release-age gating, from the cooldown support table:

Status: ❌ None

A cooldown only pays off where a compromised release can be withdrawn while the clock runs, and can only be emulated where the registry dates its releases. From the retraction table:

  • Registry: CRAN (pkg:cran)

  • Retraction: Yank, of a whole package: CRAN does not normally remove a package but archives it, which takes it out of the index install.packages() resolves against, and “older versions of packages are archived in perpetuity” (policy)

  • Publish date: ✅ tools::CRAN_package_db() carries Published and Date/Publication columns, though mpm reads no release-age gate from them

With --cooldown set, mpm skips this manager’s install and upgrade operations rather than run them unguarded (fail-closed); --cooldown best-effort opts back in.

Reference traces

A collection of raw native outputs captured from the manager’s own CLI and recorded in the bundled definition. If you know R packages well and a transcript below looks wrong, or a newer release changed its output format, report it.

$ Rscript -e options(warn = 2L); r <- getOption("repos"); if (is.na(r["CRAN"]) || r["CRAN"] == "@CRAN@") { r["CRAN"] <- "https://cloud.r-project.org"; options(repos = r) }; w <- Filter(function(l) file.access(l, 2L) == 0L, .libPaths()) -e p <- installed.packages(lib.loc = w); p <- p[!duplicated(p[, "Package"]) & (is.na(p[, "Priority"]) | p[, "Priority"] != "base"), , drop = FALSE]; cat(sprintf("%s %s\n", p[, "Package"], p[, "Version"]), sep = "")
praise 1.0.0
R6 2.5.1
$ Rscript -e options(warn = 2L); r <- getOption("repos"); if (is.na(r["CRAN"]) || r["CRAN"] == "@CRAN@") { r["CRAN"] <- "https://cloud.r-project.org"; options(repos = r) }; w <- Filter(function(l) file.access(l, 2L) == 0L, .libPaths()) -e o <- old.packages(lib.loc = w); if (!is.null(o)) { o <- o[!duplicated(o[, "Package"]), , drop = FALSE]; cat(sprintf("%s %s %s\n", o[, "Package"], o[, "Installed"], o[, "ReposVer"]), sep = "") }
R6 2.5.1 2.6.1
$ Rscript -e options(warn = 2L); r <- getOption("repos"); if (is.na(r["CRAN"]) || r["CRAN"] == "@CRAN@") { r["CRAN"] <- "https://cloud.r-project.org"; options(repos = r) }; w <- Filter(function(l) file.access(l, 2L) == 0L, .libPaths()) -e a <- available.packages(); q <- tolower(commandArgs(TRUE)[1L]); a <- a[grepl(q, tolower(a[, "Package"]), fixed = TRUE), , drop = FALSE]; cat(sprintf("%s %s\n", a[, "Package"], a[, "Version"]), sep = "") {query}
appraise 0.1.1
praise 1.0.0
reappraised 0.2

Version check

The version is probed by running:

$ Rscript --version
Rscript (R) version 4.5.2 (2025-10-31)

and extracted with:

r"version\s+(?P<version>\d+\.\d+\.\d+)"

Changelog

  • 8.3.0.dev0 (unreleased)

    • Add the R package manager, driving install.packages() through Rscript for installed, outdated, search, install, upgrade and remove.