R package workflow


A step-to-step guide to make CRAN-worthy R packages


Chi Zhang


May 19, 2023

This checklist is being updated over time. Mostly for my own use; but great if it helps you as well!

For a complete treatment, please refer to R Packages (2e) by Hadley Wickham and Jennifer Bryan.

Overview of my current workflow
  • initialize project, edit DESCRIPTION, search and replace with your package name
  • create package planning documentation, put inside dev/
  • create a minimal function with documentation, test and vignette
  • build package, check
  • create data related files and documentation
  • build pkgdown website
  • build package, check
  • push to github, deploy pkgdown website
  • github action configure lifecycle and R CMD check

Start building your package

The usethis package will help with the procedure when you do not have a package yet.

You can also create a template, and copy paste from it in the future.

Initialize the project


It opens a new R project (directory) named pkgname, with the following items:

  • directory R/
  • .Rbuildignore and .gitignore
  • and the project icon, pkgname.Rproj.

If you have an existing R project but wish to build a package there, copy everything but pkgname.Rproj, and modify the files in your existing pkg directory. Pay extra attention to the hidden files like .Rbuildignore.

usethis::use_mit_license() # modify name to yours
usethis::use_readme_md() # if you do not have this already

# create a folder for future data documentation
x <- 1 

In addition, URL and bug reports should be added in the DESCRIPTION.


It is good practice to start with planning the package, rather than directly start coding.

Create a folder called dev. To prevent it from being built, add the following line in .Rbuildignore

Write, test and document

Create exported functions in R/, development code in script/ (or somewhere else, such as dev/).

Data: raw and processed

Need to be clear in mind where the data files go. There are a few data related folders:

  • raw data files, in the format of excel sheets or csv. Usually placed as inst/data_name.csv
  • R scripts to process the raw data so that we create data object inside the package, put inside data-raw
  • data objects that can be called as pkg::data_name, are placed in data. These files are usually directly generated by executing write.rda().
  • data documentation, usually placed in R/data_documentation.R. These are Roxygen2 documents for the data.


You need to configure the Build tools.

These three things should be done:

Function documentation

Create a function f1, and put your cursor on it. Go to Code -> Insert Roxygen Skeleton to create the template.

Alternatively, use #' to start.

#' A simple placehold function 
#' @param x a numeric value
#' @return a value 3 greater than the input
#' @export
#' @examples 
#' f1(5)
f1 <- function(x){

Data documentation

It can be beneficial to create a separate file to document data only, say data_documentation.R under the R/ directory.

#' Placeholder data x
#' This dataset contains one value, x
#' @format
#' \describe{
#' \item{x}{The placeholder data x}
#' }
#' @examples
#' print(x)

Vignette documentation


Deploy to pkgdown

Check this reference here

Build package and check

It is possible that your checks don’t pass on the first try.

What to ignore when build?


Don’t forget to check these!

These aspects are quite important to check as well: documentation, code quality, exceptions among others.


Sufficient, working examples

  • README.md
  • Help pages
  • Vignettes

Example code coverage, covr::package_coverage(), use GHA workflow to check if code coverage is above a threshold.

Detect broken README examples by generating README.md on every commit.

In help pages, some examples have tags:

  • \dontrun{}: not run by example(), not run by R CMD check
  • \donttest{}: run by example() but not checked
  • \dontshow{}: run and checked
# code coverage
covr::package_coverage(type = c('examples', 'vignettes'), commentDonttest = F, commentDontrun = F)

# readme examples
rmarkdown::render("README.rmd", output_format = rmarkdown::github_document())

# help page examples
devtools::run_examples(run_dontrun = T, run_donttest = T)

# check vignette examples

Handling exceptions

Error > warning > message

Code quality

Style guide, styler::style_pkg() enforces tidyverse style guide.

Lint (code smells). Can be removed with styler

# code quality assessment
lint(text = 'x = 1') # with lint
lint(text = 'x <- 1') # no lint

CRAN Submission

Final checks

When you are almost ready to submit your package to CRAN, you need to do a few checks.

A good practice is to check while you build your package, so that you’ve already fixed most of the problems by the time you do the final check.

These are a few final checks to do.

# spell check

# windows check

# rhub cran check 

Remember to check your email and fix potential problems! Some problems pop up in different places, so make sure you fix as many as possible.


There are a few ways to submit. I found this one to be the most convenient way:


It asks a few questions to remind you whether all the checks havve passed, and whether you’ve updated the relevant information in DESCRIPTION, NEWS. In the end, it creates a tar ball and submits automatically to CRAN.

You need to check your email to confirm submission, just like when you do it manually via the webform.

Alternatively, you can either

  • write R CMD build PKGNAME in the terminal;
  • in Rstudio, in Build tab select build binary.

Afterwards, submit manually via the webform.