Introduction

Published

2026-08-06

Using R package development practices will boost your productivity when building applications and make it easier for your collaborators. First, you will have a clear structure for your files. Second, others can easily share and use your work.

A guiding principle in this book comes from the Benjamin Franklin quote,

“A place for everything, everything in its place”

Packages help you

Do future you a favor.

Standardizing your projects helps anyone reading your code, especially future you. By structuring every Shiny app like an R package, you save time on setup (or re-orienting yourself to each project’s structure). Clear code is essential for Shiny applications in production, and using an R package is a common way to organize your code.1

a package [is] the fundamental unit of shareable, reusable, and reproducible R code.” - R Packages, 2ed

If you’re using RStudio or Positron, the package structure lets you access user-friendly tools for developing Shiny applications. These tools help you develop and test functions, run unit tests, store data, manage dependencies, and create documentation.

Packages help them

Assume someone else will read your code.

R packages provide a standardized way to enhance R’s capabilities, allowing others to install and use them in their R environment. When developing Shiny apps for production deployment, it’s important to remember that the code will likely be accessed and used by others.

To quote Marie Kondo, the de-cluttering expert,

“Ensuring that each one of your belongings has its own spot is the only way to maintain a tidy and clutter-free home. Clutter has nothing to do with what or how much you own – it’s the failure to put things back where they belong.”

R packages simplify sharing your work with colleagues by eliminating the need for them to determine where everything is located, how everything connects, and how it works.

‘Production’ usually means passing the code from your personal development environment into your company’s cloud-based server environment, which typically involves bundling your app in a structure that can be shared, installed, tested, and launched.

I think the easiest way to think about it for me is that we develop a model in one computational environment–think of this as maybe your laptop or maybe you work in a server environment–still, it’s in one place, and it turns out the software that you need to have installed there is about tuning, training, etc. Putting something into production is getting it out of that computational environment and successfully carrying it over to a new computational environment. For many people, this might be like a cloud computing environment. It might be some kind of server your organization has, and we need to take it, lift it, and then successfully have it working.’ - Julia Silge, What is ‘production’ anyway? MLOps for the curious (SatRdays London 2023))

I’ve added emphasis and edited this for clarity.

Packages are scalable

Great R packages solve common problems.

If you’ve developed R functions for tasks such as analysis, data visualization, or report generation, consider creating a package instead of using source() to load them. This approach will help you expand your understanding from specific use cases (e.g., “this code performs a specific task”) to a broader perspective (e.g., “this package can perform various tasks”).

The advantage of having a mental model for R packages is that you will often observe similarities in common problems. Developing packages that address and solve frequent issues in your workflow can lead to some of the most valuable and popular contributions, as seen with packages like datapasta and reprex`.

Packages to know

I highly recommend reading and bookmarking the Shiny articles and the sites for the core package development tools:

  1. devtools
  2. pkgbuild
  3. pkgload
  4. rcmdcheck
  5. revdepcheck
  6. roxygen2
  7. remotes
  8. sessioninfo
  9. usethis

How to read this book

Transitioning from programming in R to building Shiny applications and writing R packages presents a steep learning curve. The chapters in this book are aimed flattening the package development portion of that curve. As with any new skill, app-package development involves new mental models, concepts, terminology, habits, and details. If you find yourself getting frustrated, I recommend the 15 minute rule:

“By forcing yourself to try for 15 minutes, you gain a deeper understanding of what you’re troubleshooting so that, even if you don’t fix it in 15, next time you’re in a better position to troubleshoot than you were the last time.

And by forcing yourself to ask for help after 15, you not only limit the amount of banging-your-head time, but you also get to see how the other person solves the problem while all the details are still fresh in your mind, so that you’ll more likely have a deeper understanding of why what you were doing to fix it wasn’t working, and why the ultimate solution actually worked.” - Hacker News, 2013

The chapters in this book (roughly) represent the steps of R package development, but through the lens of an existing Shiny application.2 Each topic can be applied to creating a new app-package, but–in my experience–many Shiny developers have existing applications they’d like to convert into an R package.

The stable stuff

The first two sections contain topics that aren’t likely to change anytime soon. Introduction covers the development of a Shiny app project and it’s gradual progression of complexity to warrant an R package. The app-packages section applies the key components of R package development to a Shiny app.

  • 1  Whole app game is a ‘whole game’ for the development of a toy app-package. This chapter gives a high-level overview of the app-package development workflow.3

  • In 2  Shiny we’ll dive into shiny development, focusing on the files and folders found in most Shiny applications.

  • R packages are introduced in 3  Packages, and it covers the differences between Shiny app projects, R packages, and Shiny app-packages.

  • 4  Development introduces devtools and the app-package development workflow.

  • 5  Documentation covers documenting the application’s utility functions, modules, UI, server, and standalone app function using roxygen2.

  • Managing dependencies (both imports and exports) using the NAMESPACE file is introduced in 6  Dependencies

  • 7  Data discusses the storage, format, and documentation of data files your app-package.

  • There are multiple ways to launch an application from an app-package. 8  Launch covers options to include in the app.R file and your standalone app function.

  • 9  Resources covers the many uses of the inst/ folder in R packages. This chapter also covers how to add external files and resources to your application.

The opinionated bits

The sections below represent my approach to developing app-packages. Most of these practices come from the same resources referenced above, but there are many ways to debug and test your code.

Debugging is an important part of development, both for R packages and Shiny apps. This section contains chapters on using an interactive debugger and other methods for ensuring you can reliably investigate and address bugs in your code quickly and effectively.

  • 10  Debuggers covers using R’s interactive debugger, browser(), to pause execution and inspect a Shiny app’s reactive values, then applies it in a worked example with the ggplot2movies app.

  • 11  Print debugging explains print debugging techniques, including wrapping print() and cat() in observe() and using reactiveValuesToList() to expose an app’s reactive values in the UI.

  • 12  Debugging apps gives strategies for debugging Shiny app-package modules, covering UI function debugging, server function debugging, and diagnosing communication between modules.

  • 13  Logging describes how to add structured logging to your app-package with base R and the logger package, a strategy that complements interactive and print debugging in production environments.

While developing your application, you’ll want to ensure it’s features are documented and tested. The Tests section covers testing:

  • Before running any tests we need to set up the test suite in our app-package. 14  Test suite briefly covers setting up the testing infrastructure with testthat.

  • Knowing what features to implement and what tests to develop reduces the chances of writing code that doesn’t address a user needs. 15  Specifications discusses how to identify user specifications, features, and functional requirements. It also briefly introduces behavior-driven development.

  • 16  Test tools covers how to include testing tools (fixtures and helpers) in your test suite to ensure isolated yet controllable test conditions.

  • Reactivity makes testing modules tricky. In 17  Testing modules, I’ll cover some strategies and approaches for verifying that your modules are communicating correctly with Shiny’s testServer() function.

  • 18  System tests introduces performing system (or end-to-end) tests in you app-package with the shinytest2 package.

After you’ve developed your Shiny App-Package, you’ll likely want to deploy it (or put it ‘into production’). A selection of popular methods are covered in Deploy:

  • 19  shinyapps.io describes publishing an app-package to shinyapps.io with the rsconnect package, and how to read the deploy and app logs to troubleshoot a failed or misbehaving deployment.

  • 20  Docker explains how build Docker images and containers using Docker desktop. These topics are also covered in 23  golem.

  • 21  GitHub Actions covers continuous integration (CI) / continuous deployment (CD) for Shiny app-packages using GitHub Actions.

  • 22  pkgdown websites are an excellent way to enhance it’s visibility and usability of your app-package (and it’s made seamless with usethis and GitHub actions (see Deploying your site)).

Frameworks

If you’re Googling ‘what is the best way to build a Shiny application?’ you’ll eventually encounter a Shiny framework. This section contains the development workflow and methods for three popular Shiny application frameworks (golem, leprechaun, charpente and rhino).

  • 23  golem covers developing an application using the golem framework (which is introduced in Engineering Production-Grade Shiny Apps).

  • For developers looking for a ‘lightweight’ version of the golem package, 24  leprechaun introduces the leprechaun package and development workflow

  • 25  rhino covers how to build a rhino application (which is not technically a package, but is still worth including based on it’s popularity and features).

LLM tools

The LLM tools section covers using LLM-assisted tools during app-package development, from the Shiny Assistant chatbot to the ellmer package and the chores and gander packages by Simon Couch.

  • 26  Shiny Assistant covers the Shiny Assistant, an AI-powered chatbot that can build a Shiny application from scratch or make changes to an existing one.

  • 27  ellmer introduces the ellmer package, which gives us access to LLM providers and serves as the backbone for the other LLM tools covered in this section (chores, gander, and btw).

  • 28  chores covers the chores package, an RStudio and Positron addin for repetitive, hard-to-automate tasks like writing roxygen2 documentation and testthat tests.

  • 29  gander introduces the gander package, which reads context directly from your R environment and the open file you’re working in, letting you ask questions about your code in-place instead of supplying context via a prompt.

  • 30  🏗 btw (this chapter is under construction)

Special topics

The special topics section includes a handful of topics on development, UI developement tools, code styling, storing and retrieving data, reading error outputs, using R6 objects, and keeping track of dependencies.


  1. David Neuzerling has a great post on the benefits of structuring your project as a package↩︎

  2. The original code and data for the application in this book comes from the Building Web Applications with Shiny (BWAS) course.↩︎

  3. R Packages, 2ed, has a similar chapter that covers developing standard R packages.↩︎