Preface

Welcome to the 2nd edition of R Packages! If you’re familiar with the 1st edition, this preface describes the major changes so that you can focus your reading on the new areas.

There are several main goals for this edition:

All content has been completely revised and updated. Many chapters are new or re-organized and a couple have been removed:

Acknowledgments

Since the first edition of R Packages was published, the packages supporting the workflows described here have undergone extensive development. The original trio of devtools, roxygen2, and testthat has expanded to include the packages created by the “conscious uncoupling” of devtools, as described in 2.2 devtools, usethis, and you. Most of these packages originate with Hadley Wickham (HW), because of their devtools roots. There are many other significant contributors, many of whom now serve as maintainers:

This book was written and revised in the open and it is truly a community effort: many people read drafts, fix typos, suggest improvements, and contribute content. Without those contributors, the book wouldn’t be nearly as good as it is, and we are deeply grateful for their help. We are indebted to our colleagues at Posit, especially the tidyverse team, for being perpetually game to discuss package development practices. The book has been greatly improved by the suggestions from our fantastic team of technical reviewers: Malcolm Barrett, Laura DeCicco, Zhian Kamvar, Tom Mock and Maëlle Salmon.

#> ── Attaching core tidyverse packages ──────────── tidyverse 2.0.0 ──
#> ✔ dplyr     1.1.4     ✔ readr     2.1.5
#> ✔ forcats   1.0.0     ✔ stringr   1.5.1
#> ✔ ggplot2   3.5.1     ✔ tibble    3.2.1
#> ✔ lubridate 1.9.4     ✔ tidyr     1.3.1
#> ✔ purrr     1.0.2     
#> ── Conflicts ────────────────────────────── tidyverse_conflicts() ──
#> ✖ dplyr::filter() masks stats::filter()
#> ✖ dplyr::lag()    masks stats::lag()
#> ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
#> Rows: 410 Columns: 3
#> ── Column specification ────────────────────────────────────────────
#> Delimiter: ","
#> chr (3): user, name, maybe_name
#> 
#> ℹ Use `spec()` to retrieve the full column specification for this data.
#> ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.

Thanks to all contributors the the first and second editions (in alphabetical order by GitHub username):

@aaelony, @aaronwolen (Aaron Wolen), @ablejec (Andrej Blejec), @adamcduncan (Adam Duncan), @adessy, @adrtod (Adrien Todeschini), @aghaynes (Alan Haynes), @agrueneberg (Alexander Grueneberg), @alejandrohagan (Alejandro Hagan), @alesantuz (Ale Santuz), @alexandrehsd (Alexandre Henrique), @alexholcombe (Alex O. Holcombe), @alexpghayes (alex hayes), @alforj (Justin Alford), @almartin82 (Andrew Martin), @aluxh (Alex Ho), @AmelZulji, @andreaphsz (Andrea Cantieni), @andrewdolman (Andrew Dolman), @andrewpbray (Andrew Bray), @AndrewsOR (John Andrews), @andycraig (Andrew Craig), @angela-li (Angela Li), @anjalisilva (Anjali Silva), @apomatix (Brad Friedman), @apreshill (Alison Presmanes Hill), @arashHaratian (Arash), @arilamstein (Ari Lamstein), @arneschillert (Arne Schillert), @arni-magnusson (Arni Magnusson), @asadow (Adam Sadowski), @ateucher (Andy Teucher), @avisser (Andy Visser), @ayormark (Adam Yormark), @azzaea (Azza Ahmed), @batpigandme (Mara Averick), @bclipp (Brian L), @beevabeeva, @behrman (Bill Behrman), @benmarwick (Ben Marwick), @BernhardKonrad (Bernhard Konrad), @bgreenwell (Brandon Greenwell), @Bisaloo (Hugo Gruson), @bklamer (Brett Klamer), @bm5tev3, @bms63 (Ben Straub), @bpbond (Ben Bond-Lamberty), @bquast (Bastiaan Quast), @Br-Johnson (Brett Johnson), @brews (Brewster Malevich), @brianrice2 (Brian Rice), @brry (Berry Boessenkool), @btruel, @calligross (Calli), @carldotac (Carl Lieberman), @carloscinelli (Carlos Cinelli), @CDCookJr, @cderv (Christophe Dervieux), @chambm (Matt Chambers), @charliejhadley (Charlie Joey Hadley), @chezou (Aki Ariga), @chsafouane (Safouane Chergui), @clente (Caio Lente), @cmarmstrong, @cooknl (CAPN), @CorradoLanera (Corrado Lanera), @craigcitro (Craig Citro), @crtahlin (Crt Ahlin), @daattali (Dean Attali), @danhalligan (Dan Halligan), @daroczig (Gergely Daróczi), @datarttu (Arttu Kosonen), @davidkane9 (David Kane), @DavisVaughan (Davis Vaughan), @deanbodenham, @dfalbel (Daniel Falbel), @dgrtwo (David Robinson), @dholstius (David Holstius), @DickStartz, @dkgaraujo (Douglas K. G. Araujo), @dlukes (David Lukes), @DOH-PXC5303 (Philip Crain), @dongzhuoer (Zhuoer Dong), @DougManuel (Doug Manuel), @dpprdan (Daniel Possenriede), @dracodoc (dracodoc), @drag05 (Dragos Bandur), @drvinceknight (Vince Knight), @dryzliang, @dyavorsky (Dan Yavorsky), @e-pet, @earino (E. Ariño de la Rubia), @echelleburns, @eeholmes (Eli Holmes), @eipi10 (Joel Schwartz), @ekbrown (Earl Brown), @EllaKaye (Ella Kaye), @EmilHvitfeldt (Emil Hvitfeldt), @eogoodwin, @erictleung (Eric Leung), @erikerhardt (Erik Erhardt), @espinielli (Enrico Spinielli), @ewan (Ewan Dunbar), @fbertran (Frederic Bertrand), @federicomarini (Federico Marini), @fenguoerbian (Chao Cheng), @fkohrt (Florian Kohrt), @florisvdh (Floris Vanderhaeghe), @floswald (Florian Oswald), @franrodalg (Francisco Rodríguez-Algarra), @franticspider (Simon Hickinbotham), @frycast (Daniel Vidali Fryer), @fsavje (Fredrik Sävje), @gajusmiknaitis, @gcpoole (Geoffrey Poole), @geanders (Brooke Anderson), @georoen (Jee Roen), @GerardTromp (Gerard Tromp), @GillesSanMartin (Gilles San Martin), @gmaubach (Georg Maubach), @gonzalezgouveia (Rafael Gonzalez Gouveia), @gregmacfarlane (Greg Macfarlane), @gregrs-uk (Greg), @grst (Gregor Sturm), @gsrohde (Scott Rohde), @guru809, @gustavdelius (Gustav W Delius), @haibin (Liu Haibin), @hanneoberman (Hanne Oberman), @harrismcgehee (Harris McGehee), @havenl (Haven Liu), @hcyvan (程一航), @hdraisma (Harmen), @hedderik (Hedderik van Rijn), @heists ((ꐦ°᷄д°)ა), @helske (Jouni Helske), @henningte (Henning Teickner), @HenrikBengtsson (Henrik Bengtsson), @heogden (Helen Ogden), @hfrick (Hannah Frick), @Holzhauer (Sascha Holzhauer), @howardbaek (Howard Baek), @howbuildingsfail (How Buildings Fail), @hq9000 (Sergey Grechin), @hrbrmstr (boB Rudis), @iangow (Ian Gow), @iargent, @idmn (Iaroslav Domin), @ijlyttle (Ian Lyttle), @imchoyoung (Choyoung Im), @InfiniteCuriosity (Russ Conte), @ionut-stefanb (Ionut Stefan-Birdea), @Ironholds (Os Keyes), @ismayc (Chester Ismay), @isomorphisms (i), @jackwasey (Jack Wasey), @jacobbien (Jacob Bien), @jadeynryan (Jadey Ryan), @jameelalsalam (Jameel Alsalam), @jameslairdsmith (James Laird-Smith), @janzzon (Stefan Jansson), @JayCeBB, @jcainey (Joe Cainey), @jdblischak (John Blischak), @jedwards24 (James Edwards), @jemus42 (Lukas Burk), @jenniferthompson (Jennifer Thompson), @jeremycg (Jeremy Gray), @jgarthur (Joey Arthur), @jimhester (Jim Hester), @jimr1603 (James Riley), @jjesusfilho (José de Jesus Filho), @jkeirstead (James Keirstead), @jmarca (James Marca), @jmarshallnz (Jonathan Marshall), @joethorley (Joe Thorley), @johnbaums (John), @jolars (Johan Larsson), @jonthegeek (Jon Harmon), @jowalski (John Kowalski), @jpinelo (Joao Pinelo Silva), @jrdnbradford (Jordan), @jthomasmock (Tom Mock), @julian-urbano (Julián Urbano), @jwpestrak, @jzadra (Jonathan Zadra), @jzhaoo (Joanna Zhao), @kaetschap (Sonja), @karthik (Karthik Ram), @KasperThystrup (Kasper Thystrup Karstensen), @KatherineCox, @katrinleinweber (Katrin Leinweber), @kbroman (Karl Broman), @kekecib (Ibrahim Kekec), @KellenBrosnahan, @kendonB (Kendon Bell), @kevinushey (Kevin Ushey), @kikapp (Kristopher Kapphahn), @KirkDSL, @KJByron (Karen J. Byron), @klmr (Konrad Rudolph), @KoderKow (Kyle Harris), @kokbent (Ben Toh), @kongdd (Dongdong Kong), @krlmlr (Kirill Müller), @kwenzig (Knut Wenzig), @kwstat (Kevin Wright), @kylelundstedt (Kyle G. Lundstedt), @lancelote (Pavel Karateev), @lbergelson (Louis Bergelson), @LechMadeyski (Lech Madeyski), @Lenostatos (Leon), @lindbrook, @lionel- (Lionel Henry), @LluisRamon (Lluís Ramon), @lorenzwalthert (Lorenz Walthert), @lwjohnst86 (Luke W Johnston), @maelle (Maëlle Salmon), @maiermarco, @maislind (David M), @majr-red (Matthew Roberts), @malcolmbarrett (Malcolm Barrett), @malexan (Alexander Matrunich), @manuelreif (Manuel Reif), @MarceloRTonon (Marcelo Tonon), @mariacuellar (Maria Cuellar), @markdly (Mark Dulhunty), @Marlin-Na (Marlin), @martin-mfg, @matanhakim (Matan Hakim), @matdoering, @matinang (Matina Angelopoulou), @mattflor (Matthias Flor), @maurolepore (Mauro Lepore), @maxheld83 (Max Held), @mayankvanani (Mayank Vanani), @mbjones (Matt Jones), @mccarthy-m-g (Michael McCarthy), @mdequeljoe (Matthew de Queljoe), @mdsumner (Michael Sumner), @michaelboerman (Michael Boerman), @MichaelChirico (Michael Chirico), @michaelmikebuckley (Michael Buckley), @michaelweylandt (Michael Weylandt), @miguelmorin, @MikeJohnPage, @mikelnrd (Michael Leonard), @mikelove (Mike Love), @mikemc (Michael McLaren), @MilesMcBain (Miles McBain), @mjkanji (Muhammad Jarir Kanji), @mkuehn10 (Michael Kuehn), @mllg (Michel Lang), @mohamed-180 (Mohamed El-Desokey), @moodymudskipper (Antoine Fabri), @Moohan (James McMahon), @MrAE (Jesse Leigh Patsolic), @mrcaseb, @ms609 (Martin R. Smith), @mskyttner (Markus Skyttner), @MWilson92 (Matthew Wilson), @myoung3, @nachti (Gerhard Nachtmann), @nanxstats (Nan Xiao), @nareal (Nelson Areal), @nattalides, @ncarchedi (Nick Carchedi), @ndphillips (Nathaniel Phillips), @nick-youngblut (Nick Youngblut), @njtierney (Nicholas Tierney), @nsheff (Nathan Sheffield), @osorensen (Øystein Sørensen), @PabRod (Pablo Rodríguez-Sánchez), @paternogbc (Gustavo Brant Paterno), @paulrougieux (Paul Rougieux), @pdwaggoner (Philip Waggoner), @pearsonca (Carl A. B. Pearson), @perryjer1 (Jeremiah), @petermeissner (Peter Meissner), @petersonR (Ryan Peterson), @petzi53 (Peter Baumgartner), @PhilipPallmann (Philip Pallmann), @philliplab (Phillip Labuschagne), @phonixor (Gerrit-Jan Schutten), @pkimes (Patrick Kimes), @pnovoa (Pavel Novoa), @ppanko (Pavel Panko), @pritesh-shrivastava (Pritesh Shrivastava), @PrzeChoj (PrzeChoj), @PursuitOfDataScience (Y. Yu), @pwaeckerle, @raerickson (Richard Erickson), @ramiromagno (Ramiro Magno), @ras44, @rbirkelbach (Robert Birkelbach), @rcorty (Robert W. Corty), @rdiaz02 (Ramon Diaz-Uriarte), @realAkhmed (Akhmed Umyarov), @reikookamoto (Reiko Okamoto), @renkun-ken (Kun Ren), @retowyss (Reto Wyss), @revodavid (David Smith), @rgknight (Ryan Knight), @rhgof (Richard), @rmar073, @rmflight (Robert M Flight), @rmsharp (R. Mark Sharp), @rnuske (Robert Nuske), @robertzk (Robert Krzyzanowski), @Robinlovelace (Robin Lovelace), @robiRagan (Robi Ragan), @Robsteranium (Robin Gower), @romanzenka (Roman Zenka), @royfrancis (Roy Francis), @rpruim (Randall Pruim), @rrunner, @rsangole (Rahul), @ryanatanner (Ryan), @salim-b (Salim B), @SamEdwardes (Sam Edwardes), @SangdonLim (Sangdon Lim), @sathishsrinivasank (Sathish), @sbgraves237, @schifferl (Lucas Schiffer), @scw (Shaun Walbridge), @sdarodrigues (Sabrina Rodrigues), @sebffischer (Sebastian Fischer), @serghiou (Stylianos Serghiou), @setoyama60jp, @sfirke (Sam Firke), @shannonpileggi (Shannon Pileggi), @Shelmith-Kariuki (Shel), @SheridanLGrant (Sheridan Grant), @shntnu (Shantanu Singh), @sibusiso16 (S’busiso Mkhondwane), @simdadim (Simen Buodd), @SimonPBiggs (SPB), @simonthelwall (Simon Thelwall), @SimonYansenZhao (Simon He Zhao), @singmann (Henrik Singmann), @Skenvy (Nathan Levett), @Smudgerville (Richard M. Smith), @sn248 (Satyaprakash Nayak), @sowla (Praer (Suthira) Owlarn), @srushe (Stephen Rushe), @statnmap (Sébastien Rochette), @steenharsted (Steen Harsted), @stefaneng (Stefan Eng), @stefanherzog (Stefan Herzog), @stephen-frank (Stephen Frank), @stephenll (Stephen Lienhard), @stephenturner (Stephen Turner), @stevenprimeaux (Steven Primeaux), @stevensbr, @stewid (Stefan Widgren), @sunbeomk (Sunbeom Kwon), @superdesolator (Po Su), @syclik (Daniel Lee), @symbolrush (Adrian Stämpfli-Schmid), @taekyunk (Taekyun Kim), @talgalili (Tal Galili), @tanho63 (Tan Ho), @tbrugz (Telmo Brugnara), @thisisnic (Nic Crane), @TimHesterberg (Tim Hesterberg), @titaniumtroop (Nathan), @tjebo, @tklebel (Thomas Klebel), @tmstauss (Tanner Stauss), @tonybreyal (Tony Breyal), @tonyfischetti (Tony Fischetti), @TonyLadson (Tony Ladson), @trickytank (Rick Tankard), @TroyVan, @uribo (Shinya Uryu), @urmils, @valeonte, @vgonzenbach (Virgilio Gonzenbach), @vladpetyuk (Vlad Petyuk), @vnijs (Vincent Nijs), @vspinu (Vitalie Spinu), @wcarlsen (Willi Carlsen), @wch (Winston Chang), @wenjie2wang (Wenjie Wang), @werkstattcodes, @wiaidp, @wibeasley (Will Beasley), @wilkinson (Sean Wilkinson), @williamlief (Lief Esbenshade), @winterschlaefer (Christof Winter), @wlamnz (William Lam), @wrathematics (Drew Schmidt), @XiangyunHuang (Xiangyun Huang), @xiaochi-liu (Xiaochi), @XiaoqiLu (Xiaoqi Lu), @xiaosongz (Xiaosong Zhang), @yihui (Yihui Xie), @ynsec37, @yonicd, @ysdgroot, @yui-knk (Yuichiro Kaneko), @Zedseayou (Calum You), @zeehio (Sergio Oller), @zekiakyol (Zeki Akyol), @zenggyu (Guangyu Zeng), @zhaoy, @zhilongjia (Zhilong), @zhixunwang, @zkamvar (Zhian N. Kamvar), @zouter (Wouter Saelens).

Conventions

Throughout this book, we write fun() to refer to functions, var to refer to variables and function arguments, and path/ for paths.

Larger code blocks intermingle input and output. Output is commented so that if you have an electronic version of the book, e.g., https://r-pkgs.org, you can easily copy and paste examples into R. Output comments look like #> to distinguish them from regular comments.

Colophon

This book was authored using Quarto inside RStudio. The website is hosted with Netlify, and automatically updated after every commit by GitHub actions. The complete source is available from GitHub.

This version of the book was built with:

library(devtools)
#> Loading required package: usethis
library(roxygen2)
library(testthat)
#> 
#> Attaching package: 'testthat'
#> The following object is masked from 'package:devtools':
#> 
#>     test_file
#> The following object is masked from 'package:dplyr':
#> 
#>     matches
#> The following object is masked from 'package:purrr':
#> 
#>     is_null
#> The following objects are masked from 'package:readr':
#> 
#>     edition_get, local_edition
#> The following object is masked from 'package:tidyr':
#> 
#>     matches
devtools::session_info()
#> ─ Session info ───────────────────────────────────────────────────
#>  setting  value
#>  version  R version 4.4.2 (2024-10-31)
#>  os       Ubuntu 22.04.5 LTS
#>  system   x86_64, linux-gnu
#>  ui       X11
#>  language (EN)
#>  collate  C.UTF-8
#>  ctype    C.UTF-8
#>  tz       UTC
#>  date     2024-12-21
#>  pandoc   2.9.2.1 @ /usr/bin/ (via rmarkdown)
#> 
#> ─ Packages ───────────────────────────────────────────────────────
#>  package     * version  date (UTC) lib source
#>  bit           4.5.0.1  2024-12-03 [1] RSPM
#>  bit64         4.5.2    2024-09-22 [1] RSPM
#>  brio          1.1.5    2024-04-24 [1] RSPM
#>  cachem        1.1.0    2024-05-16 [1] RSPM
#>  cli           3.6.3    2024-06-21 [1] RSPM
#>  colorspace    2.1-1    2024-07-26 [1] RSPM
#>  crayon        1.5.3    2024-06-20 [1] RSPM
#>  devtools    * 2.4.5    2022-10-11 [1] RSPM
#>  digest        0.6.37   2024-08-19 [1] RSPM
#>  dplyr       * 1.1.4    2023-11-17 [1] RSPM
#>  ellipsis      0.3.2    2021-04-29 [1] RSPM
#>  evaluate      1.0.1    2024-10-10 [1] RSPM
#>  fastmap       1.2.0    2024-05-15 [1] RSPM
#>  forcats     * 1.0.0    2023-01-29 [1] RSPM
#>  fs            1.6.5    2024-10-30 [1] RSPM
#>  generics      0.1.3    2022-07-05 [1] RSPM
#>  ggplot2     * 3.5.1    2024-04-23 [1] RSPM
#>  glue          1.8.0    2024-09-30 [1] RSPM
#>  gtable        0.3.6    2024-10-25 [1] RSPM
#>  hms           1.1.3    2023-03-21 [1] RSPM
#>  htmltools     0.5.8.1  2024-04-04 [1] RSPM
#>  htmlwidgets   1.6.4    2023-12-06 [1] RSPM
#>  httpuv        1.6.15   2024-03-26 [1] RSPM
#>  jsonlite      1.8.9    2024-09-20 [1] RSPM
#>  knitr         1.49     2024-11-08 [1] RSPM
#>  later         1.4.1    2024-11-27 [1] RSPM
#>  lifecycle     1.0.4    2023-11-07 [1] RSPM
#>  lubridate   * 1.9.4    2024-12-08 [1] RSPM
#>  magrittr      2.0.3    2022-03-30 [1] RSPM
#>  memoise       2.0.1    2021-11-26 [1] RSPM
#>  mime          0.12     2021-09-28 [1] RSPM
#>  miniUI        0.1.1.1  2018-05-18 [1] RSPM
#>  munsell       0.5.1    2024-04-01 [1] RSPM
#>  pillar        1.10.0   2024-12-17 [1] RSPM
#>  pkgbuild      1.4.5    2024-10-28 [1] RSPM
#>  pkgconfig     2.0.3    2019-09-22 [1] RSPM
#>  pkgload       1.4.0    2024-06-28 [1] RSPM
#>  profvis       0.4.0    2024-09-20 [1] RSPM
#>  promises      1.3.2    2024-11-28 [1] RSPM
#>  purrr       * 1.0.2    2023-08-10 [1] RSPM
#>  R6            2.5.1    2021-08-19 [1] RSPM
#>  Rcpp          1.0.13-1 2024-11-02 [1] RSPM
#>  readr       * 2.1.5    2024-01-10 [1] RSPM
#>  remotes       2.5.0    2024-03-17 [1] RSPM
#>  rlang         1.1.4    2024-06-04 [1] RSPM
#>  rmarkdown     2.29     2024-11-04 [1] RSPM
#>  roxygen2    * 7.3.2    2024-06-28 [1] RSPM
#>  scales        1.3.0    2023-11-28 [1] RSPM
#>  sessioninfo   1.2.2    2021-12-06 [1] RSPM
#>  shiny         1.10.0   2024-12-14 [1] RSPM
#>  stringi       1.8.4    2024-05-06 [1] RSPM
#>  stringr     * 1.5.1    2023-11-14 [1] RSPM
#>  testthat    * 3.2.2    2024-12-10 [1] RSPM
#>  tibble      * 3.2.1    2023-03-20 [1] RSPM
#>  tidyr       * 1.3.1    2024-01-24 [1] RSPM
#>  tidyselect    1.2.1    2024-03-11 [1] RSPM
#>  tidyverse   * 2.0.0    2023-02-22 [1] RSPM
#>  timechange    0.3.0    2024-01-18 [1] RSPM
#>  tzdb          0.4.0    2023-05-12 [1] RSPM
#>  urlchecker    1.0.1    2021-11-30 [1] RSPM
#>  usethis     * 3.1.0    2024-11-26 [1] RSPM
#>  vctrs         0.6.5    2023-12-01 [1] RSPM
#>  vroom         1.6.5    2023-12-05 [1] RSPM
#>  withr         3.0.2    2024-10-28 [1] RSPM
#>  xfun          0.49     2024-10-31 [1] RSPM
#>  xml2          1.3.6    2023-12-04 [1] RSPM
#>  xtable        1.8-4    2019-04-21 [1] RSPM
#> 
#>  [1] /home/runner/work/_temp/Library
#>  [2] /opt/R/4.4.2/lib/R/site-library
#>  [3] /opt/R/4.4.2/lib/R/library
#> 
#> ──────────────────────────────────────────────────────────────────