Using depguard in Kaggle, Colab, and on your desktop

The problem

Hosted, ephemeral R notebooks (Kaggle, Colab, Binder, and similar) ship with a large pre-installed set of packages at fixed versions. When you install an additional package, its dependencies can silently upgrade or downgrade a package that is already loaded elsewhere in your session, breaking code further down the notebook with no install-time error. The same thing happens on a normal desktop whenever you install into a library you share between projects.

Tools like renv solve this well for projects you fully own and can persist, but assume you can write lockfiles and restore a private library. That often doesn’t fit a throwaway notebook, or a quick script. depguard fills the narrower gap: lightweight checks that run entirely from locally installed metadata, so they work offline.

What is the environment?

library(depguard)
dep_env()

dep_env() detects Kaggle, Colab, Binder, RStudio and plain desktop sessions, and reports which libraries are writable. depguard uses it to word its advice (for example, how to restart the session).

Workflow 1: snapshot before, diff after

Run this before installing anything new:

snap <- dep_snapshot(path = "depguard_snapshot.rds")

Install what you need as usual:

install.packages("someNewPackage")

Then check what changed:

dep_diff(snap)

The comparison is made on the versions on disk. R keeps running the old version of an already-loaded package until you restart, so a package that changed and is still loaded is flagged risk = "high" and session_stale: code you already ran used one version, and code run after a restart will use another.

In hosted notebooks you normally have to restart the session after installing. Saving the snapshot with path lets you compare after the restart:

dep_diff("depguard_snapshot.rds")

Workflow 2: declare a manifest

If you know what your notebook needs up front, declare it once:

dep_manifest(
  dplyr = ">= 1.1.4",   # at least this version
  ggplot2 = "3.5.0",    # a bare version also means "at least"
  quantmod = "== 0.4.26" # exactly this version
)

Or pin whatever you are using right now:

library(dplyr)
dep_manifest_freeze(path = "depguard.txt")

Any file extension other than .rds produces a plain-text manifest that is easy to read, edit and commit:

# depguard manifest: package (operator version)
dplyr (== 1.1.4)

Then, any time later:

dep_check(path = "depguard.txt")

This walks the dependency tree of each declared package using only locally installed metadata and compares the version constraints that the packages declare on one another (for example, cli (>= 3.4.0)) with what is actually installed. It reports missing, mismatch, and restart (the version on disk is right but the session is still running an older one), along with which package required each dependency. In scripts and CI, use dep_check(stop_on_problem = TRUE) to fail on any problem.

Workflow 3: one-shot health check

At the top of a notebook:

dep_healthcheck()

This describes the environment, warns about packages hidden by another library, and then checks a manifest if one exists, or captures a baseline snapshot otherwise.

“I upgraded it but nothing changed”

R loads the first copy of a package it finds on the library path. A stale copy in a library earlier on the path hides the one you just installed.

dep_libraries()

Fixing a conflict

If a specific package got silently bumped and broke something, you can roll just that package back to a specific version, and preview it first:

dep_fix("stringr", "1.5.0", dry_run = TRUE)
dep_fix("stringr", "1.5.0")

dep_fix() uses pak or remotes when installed and otherwise downloads the source from the CRAN archive using only base R. It checks the result and tells you if you need to restart, or if another library is still hiding the rolled-back copy.

This performs a single-package rollback only; it does not resolve cascading conflicts the rollback might introduce elsewhere. For full dependency resolution, use renv::restore() or pak’s solver.