rlang::global_entrance()
rlang::trace_back()
rlang::try_fetch()Writing and understanding R packages can be quite challenging.
To make things easier, I’ve compiled a short list of R libraries that may be helpful for this task.1
1 This is not a comprehensive list, but there doesn’t seem to be a CRAN task view for this sort of thing and I am trying to fill this gap. The closest match might be the “Reproducible Research” CRAN Task View.
2 It’s also worth noting that the packages I cite generally lean towards those actively supported by Posit, specifically under the collection of R packages maintained under “r-lib”. This isn’t necessarily good or bad, but it’s helpful to use software that is actively maintained. The hope is that one will be able to learn the package once, then use it for a long time and in a very productive manner. Also, a highly used package is a highly tested package, which helps make for a good user experience.
I’ve only used a subset of them, but I hope to update this blog post when I figure out whether I can make them live up to my hype.2
General Packages and Resources
-
rlang-
This package has many advanced features. In particular, it can help diagnose errors by formatting them into a readable format.
-
-
generics- Promises to make the UX of your package more similar to other packages, while reducing the number of dependencies.
- The chief example is letting you write a
tidymethod, without importingbroom.
- Comparing
RObjects-
waldo-
Colorful and user-friendly comparison of R-objects.
wald::compare() Contrast with
all.equal()andidentical()
-
-
digest-
This package is unusual in that it compares objects using hashes.
digest::digest() I imagine this could be particularly useful in cases of exact numerical comparisons with no tolerance, which may sometimes occur during statistical computing.
-
-
-
lobstr-
Better than
str().
-
-
ellipsis-
The
...functionality in R is powerful in a potentially dangerous way. This package helps users understand the use of....ellipsis::check_dots_empty() ellipsis::check_dots_unnamed() ellipsis::check_dots_used()
-
-
callr-
This package helps run
Rcode in a separate process. This might be handy when you’re inside a debugging environment and want to test something.callr::r()
-
-
evaluate-
Recreates command line behavior.
Perhaps this would be helpful to recreate a point in a debugging environment?
-
-
devtools- Default package for developing
Rpackages.
- Default package for developing
-
reprex- Must-have for reporting bugs and communicating with other developers.
-
sessioninfo- A must-have for communicating with other developers and comparing environments between machines.
-
clipr-
Intermediary between
Rand your clipboard.clipr::write_clip() clipr::read_clip() Could be helpful when you’re inside a debugging environment.
-
-
datapasta- Can be used to copy data and try to read into
Rmore easily.
- Can be used to copy data and try to read into
-
Air- Format
Rcode really fast, is not a package.
- Format
-
Writing R extensions
- Classic.
-
Advanced R
- Classic.
-
R Packages
- Classic.
Benchmarking
Benchmarking is important for comparing different implementations of the same idea. It can also help with performance tuning.
-
-
Comparing performance of different functions.
bench::mark()
-
-
-
Timing specific components of functions.
profvis::profvis()
-
-
-
Also for timing specific components of functions, but apparently more sophisticated and advanced.
proftools::profileExpr() proftools::plotProfileCallGraph() proftools::flameGraph() See this vignette for how to use it.
-
Static Code Analysis
These tools analyze R code without running them. It would probably be better to use these tools rather than trying to manually map out what happens to an R object using pen-and-paper.
-
-
Linting your code.
lintr::lint()
-
-
-
See what variables and functions a
Rsource code file uses.checkglobals::checkglobals()
-
-
-
Similar to
checkglobalsandglobals.codetools::findGlobals() codetools::findLocals()
-
-
-
Similar to
checkglobalsandcodetools.globals::Globals()
-
-
-
Dependency graph of a package and/or its functions.
pkgnet::CreatePackageReport() pkgnet::CreatePackageVignette() pkgnet::DefaultReporters() pkgnet::DependencyReporter() pkgnet::FunctionReporter() pkgnet::InheritanceReporter() pkgnet::PackageReport() pkgnet::SummaryReporter()
-
-
As per the vignette, “the CodeDepends package provides a flexible framework for statically analyzing R code (i.e., without evaluating it). It also contains higher-level functionality for: detecting dependencies between R code blocks or expressions, “tree-shaking” (pruning a script down to only the expressions necessary to evaluate a given expression), plotting variable usage timelines, and more.”
-
CodeDepends::getInputs() CodeDepends::inputCollector() CodeDepends::makeCallGraph() CodeDepends::makeTaskGraph() CodeDepends::makeVariableGraph() CodeDepends::getDetailedTimelines()
-
As per the associated master thesis’ abstract, “In this master thesis we describe the construction of a backward program slicer for the R programming language. Given a variable at a specific point in the program, a so-called”slicing criterion”, the slicer returns the subset of the program that might affect the value of the variable.”
Interfaces with the external program
flowr.This seems rather sophisticated and actively developed, rather than describe it very inaccurately, it would be better for me to link to its Wiki and the associated master thesis.
Tests
Tests are important for making sure that your code really does what it’s supposed to do. There’s also the popular philosophy of ‘test driven development’, which can help guide the development of your package based on some clear criteria, meaning tests.
-
-
Test coverage for your functions.
covr::report() covr::package_coverage()
-
-
- Default testing package.
-
-
This might be more lightweight than
testthatand require less set-up.unittest::ok() unittest::ok_group() unittest::ut_cmp_equal() unittest::ut_cmp_error() unittest::ut_cmp_identical() unittest::ut_cmp_warning()
-
-
This is like an interactive
testthatthat can write to your filesystem. See this recording.-
As per the package vignette, the package “
unitizerrequires you to review test outputs and confirm they are as expected. [In contrast, the package]testthatrequires you to assert what the test outputs should be beforehand.”unitizer::unitize() demo(package = "unitizer") browseVignettes("unitizer")
-
A testing package inspired by
JUnit.A notable feature seems to be the ability to track the value of a variable.
-
It apparently changes the random number generation. See this vignette for more information.
-
- Seems similar in purpose to
unittestand similar in usage totestthat.
- Seems similar in purpose to
Debugging
Debugging is helpful when something has gone wrong/unexpected.
General Resources on debugging in R:
C/C++ and Memory Leaks
When using C/C++, in particular, these utilities may be useful:
lldbvalgrindgdb-
memtools:Something about memory leaks and analyzing memory in
R.-
Does not seem to be supported on
R4.6 as of April 29/2026memtools::mem_snapshot() memtools::mem_igraph() memtools::root_ns_registry() memtools::mem_stash() memtools::obj_address() memtools::mem_paths_shortest()
Logging
Generally, logging in R can be used to store the output of a script. For our purposes, it can be helpful for selectively understanding the state and development of an R object(s) over time–then storing this output in a human-readable format.
This can be better than manually tracking an R object(s) and making mental notes of what happens to it.
-
-
Inspired by
Log4j.log4r::logger() log4r::log_info() log4r::log_warn() log4r::log_debug() Website seems to be currently down: See https://github.com/r-lib/log4r and https://log4r.r-lib.org/dev/, instead.
-
-
-
Inspired by the
futile.loggerR package and Python’slogging.logger::log_info() logger::log_warn() logger::log_debug() logger::log_formatter() This seems to overlap substantially with
log4r.
-
-
-
Allows tracking of an
Robject and an examination of how it changes.
-
-
-
A quick glance seems to make this out to be a logger that doesn’t require as much manual fiddling of what to log.
logrx::axecute() This also seems to be part of the
pharmaverseseries of packages.
-
-
- Logging that is specific to
dplyrandtidyr.
- Logging that is specific to
-
-
An easy logger. Presumably similar to
logrx, in purpose, but is supposed to be familiar to SAS users. See the available options here.
-
-
-
As I copy pasted from the
whirlOverview:“The whirl package provide functionalities for executing scripts in batch and simultaneously getting a log from the individual executions. A log from script execution is in many pharmaceutical companies a GxP requirement, and the whirl package honors this requirement by generating a log that, among other things, contains information about:
- Status (did the script run with any error or warnings)
- The actual code itself
- Date and time of execution
- The environment the script was executed under (session info)
- Information about packages versions that was utilized
- Environmental variables
And all this is wrapped into a nicely formatted html document that is easy to navigate.”
whirl::run()
-
Printing to Command Line
-
- Formats
Rterminal output in pretty ways.
- Formats
-
- Good looking terminal output.
-
- Good looking printing of units.
-
- Good looking printing of columns.
Blog Post Computational Environment
Warning in utils::citation(pkg_name): could not determine year for 'flowr' from
package DESCRIPTION file
We used R v. 4.6.1 (R Core Team 2026) and the following R packages: bench v. 1.1.4 (Hester and Vaughan 2025), callr v. 3.7.6 (Csárdi and Chang 2024), checkglobals v. 0.1.4 (Chau 2025), clipr v. 0.8.0 (Lincoln 2022), CodeDepends v. 0.6.7 (Lang et al. 2026), codetools v. 0.2.20 (Tierney 2024), covr v. 3.6.5 (Hester 2025), crayon v. 1.5.3 (Csárdi 2024a), datapasta v. 3.1.0 (McBain et al. 2020), debugme v. 1.2.0 (Csárdi 2024b), devtools v. 2.5.1 (Wickham et al. 2026), digest v. 0.6.39 (Eddelbuettel 2025), ellipsis v. 0.3.3 (Wickham 2026a), evaluate v. 1.0.5 (Wickham and Xie 2025), flowr v. 0.0.3 (Sihler, n.d.), generics v. 0.1.4 (Wickham, Kuhn, et al. 2025), globals v. 0.19.1 (Bengtsson 2026), lintr v. 3.3.0.1 (Hester et al. 2025), lobstr v. 1.2.1 (Wickham 2026b), log4r v. 0.4.4 (White and Jacobs 2024), logger v. 0.4.1 (Daróczi and Wickham 2025), logr v. 1.3.9 (Bosak 2025), logrx v. 0.4.0 (Kosiba et al. 2025), lumberjack v. 1.3.1 (van der Loo 2021), pkgnet v. 0.6.0 (Burns et al. 2026), prettyunits v. 1.2.0 (Csardi 2023), proftools v. 0.99.3 (Tierney and Jarjour 2020), profvis v. 0.4.0 (Wickham et al. 2024), rmarkdown v. 2.31 (Xie et al. 2018, 2020; Allaire et al. 2026), RUnit v. 0.4.33.1 (Burger et al. 2025), sessioninfo v. 1.2.3 (Wickham, Chang, et al. 2025), testthat v. 3.3.2 (Wickham 2011), tidylog v. 1.1.0 (Elbers 2024), tidyverse v. 2.0.0 (Wickham et al. 2019), tinytest v. 1.4.3 (van der Loo 2020), unitizer v. 1.4.23 (Gaslam 2025), unittest v. 1.7.0 (Lentin and Hennessey 2024), waldo v. 0.6.2 (Wickham 2025), whirl v. 0.3.2 (Thomsen et al. 2026).
═ Session info ═══════════════════════════════════════════════════════════════
─ Packages ───────────────────────────────────────────────────────────────────
! package * version date (UTC) lib source
P assertthat 0.2.1 2019-03-21 [?] RSPM
P backports 1.5.1 2026-04-03 [?] RSPM
P bench * 1.1.4 2025-01-16 [?] RSPM
P BiocGenerics 0.56.0 2025-10-29 [?] Bioconduc~
P BiocManager 1.30.27 2025-11-14 [?] RSPM
P brio 1.1.5 2024-04-24 [?] RSPM
P cachem 1.1.0 2024-05-16 [?] RSPM
P callr * 3.7.6 2024-03-25 [?] RSPM
P checkglobals * 0.1.4 2025-10-01 [?] RSPM
P cli * 3.6.6 2026-04-09 [?] RSPM
P clipr * 0.8.0 2022-02-22 [?] RSPM
P clisymbols 1.2.0 2017-05-21 [?] RSPM
P CodeDepends * 0.6.7 2026-03-03 [?] RSPM
P codetools * 0.2-20 2024-03-31 [?] CRAN (R 4.6.0)
P common * 1.1.5 2026-02-23 [?] RSPM
P covr * 3.6.5 2025-11-09 [?] RSPM
P crayon * 1.5.3 2024-06-20 [?] RSPM
P data.table 1.18.2.1 2026-01-27 [?] RSPM
P datapasta * 3.1.0 2020-01-17 [?] RSPM
P debugme * 1.2.0 2024-04-25 [?] RSPM
P devtools * 2.5.1 2026-04-16 [?] RSPM
P diffobj 0.3.6 2025-04-21 [?] RSPM
P digest * 0.6.39 2025-11-19 [?] RSPM
P dplyr 1.2.1 2026-04-03 [?] RSPM
P DT 0.34.0 2025-09-02 [?] RSPM
P ellipsis * 0.3.3 2026-04-04 [?] RSPM
P evaluate * 1.0.5 2025-08-27 [?] RSPM
P fastmap 1.2.0 2024-05-15 [?] RSPM
P flowr * 0.0.3 2026-04-29 [?] Github (flowr-analysis/flowr-r-adapter@b171729)
P fs 2.1.0 2026-04-18 [?] RSPM
P generics * 0.1.4 2025-05-09 [?] RSPM (R 4.6.0)
P globals * 0.19.1 2026-03-13 [?] RSPM
P glue 1.8.1 2026-04-17 [?] RSPM
P graph 1.88.1 2025-12-08 [?] Bioconduc~
P grateful * 0.3.0 2025-09-04 [?] RSPM
P htmltools 0.5.9 2025-12-04 [?] RSPM
P htmlwidgets 1.6.4 2023-12-06 [?] RSPM
P httr 1.4.8 2026-02-13 [?] RSPM
P igraph 2.3.0 2026-04-21 [?] RSPM
P jsonlite 2.0.0 2025-03-27 [?] RSPM
P knitr 1.51 2025-12-20 [?] RSPM
P lattice 0.22-9 2026-02-09 [?] CRAN (R 4.6.1)
P lifecycle 1.0.5 2026-01-08 [?] RSPM
P lintr * 3.3.0-1 2025-11-27 [?] RSPM
P lobstr * 1.2.1 2026-04-04 [?] RSPM
P log4r * 0.4.4 2024-10-12 [?] RSPM
P logger * 0.4.1 2025-09-11 [?] RSPM
P logr * 1.3.9 2025-03-26 [?] RSPM
P logrx * 0.4.0 2025-05-05 [?] RSPM
P lumberjack * 1.3.1 2023-03-29 [?] RSPM
P magrittr 2.0.5 2026-04-04 [?] RSPM
P Matrix 1.7-5 2026-03-21 [?] CRAN (R 4.6.1)
P memoise 2.0.1 2021-11-26 [?] RSPM
P otel 0.2.0 2025-08-29 [?] RSPM
P pillar * 1.11.1 2025-09-17 [?] RSPM
P pkgbuild 1.4.8 2025-05-26 [?] RSPM
P pkgconfig 2.0.3 2019-09-22 [?] RSPM
P pkgload 1.5.2 2026-04-22 [?] RSPM
P pkgnet * 0.6.0 2026-01-27 [?] RSPM
P png 0.1-9 2026-03-15 [?] RSPM
P prettyunits * 1.2.0 2023-09-24 [?] RSPM
P processx 3.9.0 2026-04-22 [?] RSPM
P proftools * 0.99-3 2020-07-08 [?] RSPM
P profvis * 0.4.0 2024-09-20 [?] RSPM
P ps 1.9.3 2026-04-20 [?] RSPM
P purrr 1.2.2 2026-04-10 [?] RSPM
P R6 2.6.1 2025-02-15 [?] RSPM
P Rcpp 1.1.1-1.1 2026-04-24 [?] RSPM
P renv 1.2.2 2026-04-16 [?] RSPM
P reprex * 2.1.1 2024-07-06 [?] RSPM
P reticulate 1.46.0 2026-04-09 [?] RSPM
P rex 1.2.2 2026-03-28 [?] RSPM
P rlang * 1.2.0 2026-04-06 [?] RSPM
P rmarkdown 2.31 2026-03-26 [?] RSPM
P RUnit * 0.4.33.1 2025-06-17 [?] RSPM
P sessioninfo * 1.2.3 2025-02-05 [?] RSPM
P stringi 1.8.7 2025-03-27 [?] RSPM
P stringr 1.6.0 2025-11-04 [?] RSPM
P testthat * 3.3.2 2026-01-11 [?] RSPM
P tibble 3.3.1 2026-01-11 [?] RSPM
P tidylog * 1.1.0 2024-05-08 [?] RSPM
P tidyr 1.3.2 2025-12-19 [?] RSPM
P tidyselect 1.2.1 2024-03-11 [?] RSPM
P tinytest * 1.4.3 2026-03-24 [?] RSPM
P unitizer * 1.4.23 2025-10-22 [?] RSPM
P unittest * 1.7-0 2024-08-16 [?] RSPM
P usethis * 3.2.1 2025-09-06 [?] RSPM
P vctrs 0.7.3 2026-04-11 [?] RSPM
P visNetwork 2.1.4 2025-09-04 [?] RSPM
P waldo * 0.6.2 2025-07-11 [?] RSPM
P whirl * 0.3.2 2026-01-21 [?] RSPM
P withr 3.0.2 2024-10-28 [?] RSPM
P xfun 0.57 2026-03-20 [?] RSPM
P XML 3.99-0.23 2026-03-20 [?] RSPM
P xml2 1.5.2 2026-01-17 [?] RSPM
P yaml 2.3.12 2025-12-10 [?] RSPM
[1] /home/mstruong/Documents/RStudio/website/emstruong.github.io/renv/library/linux-ubuntu-jammy/R-4.6/x86_64-pc-linux-gnu
[2] /home/mstruong/.cache/R/renv/sandbox/linux-ubuntu-jammy/R-4.6/x86_64-pc-linux-gnu/e7c0fad7
* ── Packages attached to the search path.
P ── Loaded and on-disk path mismatch.
──────────────────────────────────────────────────────────────────────────────
References
Reuse
Citation
@online{truong2025,
author = {Truong, Michael S.},
title = {Resources and {Tools} for {Writing} {Your} {Own} and
{Understanding} {Other} {People’s} {R} {Packages} (2025)},
date = {2025-09-17},
langid = {en}
}