Running R in GitHub Actions
GitHub Actions lets you automate R workflows directly in your repository. Whether you’re checking an R package, running tests, or building documentation, CI saves time and catches problems early. This guide covers the essentials for running R in GitHub Actions.
Setting up R in GitHub actions
The r-lib/actions repository provides ready-made workflows for R projects. Start with the setup-R action:
steps:
- uses: actions/checkout@v4
- uses: r-lib/actions/setup-r@v2
with:
r-version: '4.3'
This checks out your code and installs the specified R version. You can also use "devel" for the development version or a matrix strategy to test against multiple R versions.
Installing R packages
Package installation is typically the slowest step in R CI. Use the setup-renv action to cache your dependencies:
- uses: r-lib/actions/setup-renv@v2
This restores packages from a lockfile (renv.lock), dramatically speeding up subsequent runs. If you prefer not to use renv, the setup-r action includes basic caching:
- uses: r-lib/actions/setup-r@v2
with:
r-version: '4.3'
cache: true
The cache: true option caches the user library between runs based on yourDESCRIPTION file.
Running R CMD check
The standard way to validate an R package is R CMD check. The r-lib/actions repository provides a dedicated action:
- uses: r-lib/actions/check-r-package@v2
This action runs a full R CMD check with proper settings for CI environments. It handles OS-specific differences and configures the environment appropriately.
For more control, you can run check manually:
- name: Run R CMD check
run: |
R CMD build .
R CMD check *_*.tar.gz
shell: Rscript {0}
Running tests with testthat
If you’re using testthat for unit tests, run them in your workflow:
- name: Run tests
run: |
library(testthat)
library(yourpackage)
test_dir("tests/testthat")
shell: Rscript {0}
Or use the dedicated test action:
- uses: r-lib/actions/setup-r-dependencies@v2
with:
extra-packages: testthat
- name: Test package
run: |
library(testthat)
test_check("yourpackage")
shell: Rscript {0}
The setup-r-dependencies action installs packages listed in your Description file, making it easy to set up your test environment.
Building pkgdown sites
Many R packages host their documentation on GitHub Pages using pkgdown. Here’s a complete workflow:
name: pkgdown
on:
push:
branches: [main]
jobs:
pkgdown:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: r-lib/actions/setup-r@v2
- uses: r-lib/actions/setup-renv@v2
- name: Build site
run: pkgdown::build_site()
shell: Rscript {0}
- name: Deploy to GitHub Pages
uses: peaceiris/actions-gh-pages@v3
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./docs
This builds your pkgdown site on every push to main and deploys it to GitHub Pages. Make sure to enable GitHub Pages in your repository settings.
Rendering Quarto and R markdown
For Quarto documents or R Markdown reports, use an appropriate rendering step:
- name: Render Quarto
run: quarto::quarto_render("report.qmd")
shell: Rscript {0}
- name: Render R Markdown
run: rmarkdown::render("report.Rmd")
shell: Rscript {0}
Add dependencies to your workflow as needed:
- name: Install Quarto
uses: quarto-dev/quarto-actions/setup@v2
with:
version: 1.4
Caching strategies
Package installation is expensive. Here are two caching approaches:
Using renv (Recommended)
- uses: r-lib/actions/setup-renv@v2
Commit your renv.lock file to the repository. The action restores the exact package versions on each run.
Using setup-r with cache
- uses: r-lib/actions/setup-r@v2
with:
cache: true
This caches your library based on your DESCRIPTION file. It’s simpler but less precise than renv.
For maximum speed, combine both—use setup-renv for reproducibility and add a manual cache step for additional packages:
- uses: actions/cache@v4
with:
path: ~/.local/bin
key: ${{ runner.os }}-quarto-${{ hashFiles('*.qmd') }}
Complete example: R package CI
Here’s a full workflow that combines several elements:
name: R Package CI
on:
push:
branches: [main, master]
pull_request:
branches: [main, master]
jobs:
test:
runs-on: ${{ matrix.config.os }}
strategy:
fail-fast: false
matrix:
config:
- { os: ubuntu-latest, r: '4.3' }
- { os: ubuntu-latest, r: '4.2' }
- { os: macOS-latest, r: '4.3' }
- { os: windows-latest, r: '4.3' }
steps:
- uses: actions/checkout@v4
- uses: r-lib/actions/setup-r@v2
with:
r-version: ${{ matrix.config.r }}
- uses: r-lib/actions/setup-renv@v2
- name: Run tests
run: |
library(testthat)
test_check("mypackage")
shell: Rscript {0}
- name: Run R CMD check
run: |
R CMD build .
R CMD check *_*.tar.gz --as-cran
shell: Rscript {0}
This runs tests and checks on multiple R versions and operating systems. Adjust the matrix based on your package’s compatibility requirements.
Common patterns
The r-lib/actions repository provides reusable GitHub Actions steps for R. The most used are setup-r, setup-r-dependencies, and check-r-package. A minimal package CI workflow installs R, restores the renv lockfile or installs dependencies from DESCRIPTION, runs R CMD check, and reports results.
For matrix testing across R versions, use the matrix strategy with r-version: [release, devel, oldrel-1]. The {r-lib/pkgdown} action builds and deploys a pkgdown site to GitHub Pages on push to the default branch.
Secrets for deployment (Posit Connect API keys, repository tokens) go in repository or organization secrets and are accessed with ${{ secrets.MY_SECRET }}. Never hardcode credentials in workflow files.
R-Specific GitHub actions
The r-lib/actions repository provides pre-built GitHub Actions for R packages. r-lib/actions/setup-r@v2 installs R with specified version and CRAN mirrors. r-lib/actions/setup-r-dependencies@v2 installs package dependencies from DESCRIPTION, with caching. r-lib/actions/check-r-package@v2 runs R CMD check.
A minimal R package CI workflow:
on: [push, pull_request]
jobs:
R-CMD-check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: r-lib/actions/setup-r@v2
- uses: r-lib/actions/setup-r-dependencies@v2
- uses: r-lib/actions/check-r-package@v2
usethis::use_github_actions() writes this workflow file automatically. For more complex setups, usethis::use_github_actions("check-full") runs on multiple OS and R version combinations.
Caching dependencies
Installing R packages from source is slow. Caching the package library between runs saves minutes. r-lib/actions/setup-r-dependencies@v2 handles caching automatically, it uses the package DESCRIPTION and NAMESPACE as the cache key, invalidating when dependencies change.
Manual caching with actions/cache@v4:
- uses: actions/cache@v4
with:
path: ${{ env.R_LIBS_USER }}
key: ${{ runner.os }}-r-${{ hashFiles('DESCRIPTION') }}
Renv users: renv::restore() with the renv.lock as the cache key ensures exact reproducibility. The r-lib/actions/setup-renv@v2 action handles this pattern.
Rendering and publishing reports
Quarto documents and R Markdown reports can be rendered and published by GitHub Actions. Render on push, then deploy to GitHub Pages:
- name: Render Quarto
run: quarto render report.qmd
- name: Deploy to Pages
uses: peaceiris/actions-gh-pages@v3
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./
For shinyapps.io deployment: rsconnect::deployApp() with credentials stored as GitHub secrets. Set the secrets as environment variables and call the deploy function in a workflow step.
Scheduled and manual triggers
on: schedule: cron: "0 6 * * 1" runs every Monday at 6 AM. This is appropriate for scheduled report rendering, dependency update checks (usethis::use_version_update_action()), and periodic data pipeline runs.
on: workflow_dispatch adds a “Run workflow” button to the GitHub Actions UI, enabling manual triggering with optional input parameters. Inputs are defined under inputs: in the trigger and accessed as ${{ github.event.inputs.param_name }} in the workflow.
Conditional steps: if: github.ref == 'refs/heads/main' runs a step only on the main branch. This prevents deployment steps from running on feature branches.
CI for R projects
Continuous integration for R runs your package checks, tests, and documentation builds automatically on every push. The r-lib/actions GitHub Actions repository provides pre-built action steps for the most common R CI tasks: installing R, installing dependencies with pak, running check, running tests with coverage, and building pkgdown documentation. Using these actions is faster than writing equivalent shell scripts because they handle R-specific details like system library installation and CRAN mirror selection.
A minimal R package CI workflow installs R, installs the package dependencies, and runs R CMD check. Failures in R CMD check produce workflow failures that block merging. The most common CI failures are missing system dependencies that were installed locally but not in the CI environment, encoding issues in documentation, and tests that pass locally but fail due to platform differences.
Package caching
R package installation is slow. A clean CI run for a package with many dependencies can spend more time installing packages than running tests. GitHub Actions caches the installed packages between runs, the r-lib/actions/setup-r-dependencies action handles this automatically using a lockfile. When the dependency lockfile has not changed, the cached packages are restored and installation is skipped.
Cache hits are not guaranteed. The cache is keyed on the lockfile hash and the R version. Updating a package, changing the R version, or the cache being evicted by GitHub all invalidate the cache and trigger a full reinstall. For packages with many heavy dependencies, keeping the dependency set minimal improves both cache hit rates and CI run times on cache misses.
Matrix testing
Testing across multiple R versions and operating systems catches platform-specific bugs. A matrix strategy in the workflow file runs the same job on every combination of R version and OS in the matrix. The r-lib/actions configuration provides a standard matrix that covers the latest release, the development version, and the previous release on Ubuntu, macOS, and Windows.
Matrix builds multiply CI minutes. Running three OS by three R version combinations produces nine concurrent jobs. For packages where platform compatibility is critical, those that link to C/C++ code or interact with system APIs, the full matrix is worthwhile. For pure R packages with standard dependencies, testing on Ubuntu with the latest R version plus a single Windows run covers the most important compatibility cases at lower cost.
Conclusion
GitHub Actions provides powerful CI/CD for R projects. Start with the r-lib actions—they’re maintained by the R community and handle the nuances of R environments. Focus on caching package installations, using renv for reproducibility, and automating the checks that matter for your project. Once configured, your R package CI will catch issues automatically on every push.
See also
- Building R Packages, Learn the fundamentals of creating and structuring R packages.
- Using renv for Project Dependencies — Manage R package versions with renv for reproducible environments.
- Writing R Packages with devtools — Streamline your package development workflow.