targets, renv, and GitHub Actions
2026-05-14
| Problem | Tool | What it protects against |
|---|---|---|
| “What order do I run the scripts in?” | targets |
Hidden dependencies, stale outputs |
| “Why does this work on my machine but not yours?” | renv |
Package version drift |
| “How do I know this still works?” | GitHub Actions | Silent breakage, collaboration risk |
Analytical question: How do body mass patterns differ among penguin species and islands?
Illustration by Allison Horst
The workflow produces:
The pipeline defines what the products are and how to make them.
| Location | Purpose |
|---|---|
_targets.R |
Defines the workflow |
R/ |
Stores reusable analysis functions |
reports/ |
Quarto reports that consume pipeline outputs |
slides/ |
Presentation materials |
renv.lock |
Records package versions |
.github/workflows/ |
Automated checks |
outputs/ |
Derived analysis products |
targets turns an analysis into a pipelineScript sequence
This order is a convention. It is not enforced.
targets::tar_visnetwork() renders this interactively.
If clean_penguins_data() changes, targets rebuilds:
clean_penguinsspecies_summary, island_summarybody_mass_plot, body_mass_modelreportrenv records the project environmentThe lockfile becomes part of the reproducible record — commit it.
| File or folder | Commit? | Why |
|---|---|---|
renv.lock |
✅ Yes | Records package versions |
renv/activate.R |
✅ Yes | Activates the project environment |
renv/settings.json |
✅ Yes | Records project renv settings |
renv/library/ |
❌ No | Local package cache; machine-specific |
name: Run targets workflow
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
run-targets:
runs-on: ubuntu-latest
steps:
- name: Check out repository
uses: actions/checkout@v4
- name: Set up R
uses: r-lib/actions/setup-r@v2
with:
r-version: '4.5.2'
use-public-rspm: true
- name: Set up pandoc
uses: r-lib/actions/setup-pandoc@v2
- name: Set up Quarto
uses: quarto-dev/quarto-actions/setup@v2
- name: Install system dependencies
run: sudo apt-get install -y libglpk-dev
- name: Restore R package environment
uses: r-lib/actions/setup-renv@v2
- name: Run targets pipeline
run: Rscript -e 'targets::tar_make()'CI helps confirm
CI does not confirm
| Layer | Question it answers |
|---|---|
| Repository structure | Where is everything? |
| R functions | What does each step do? |
targets |
What depends on what? |
renv |
What software versions are needed? |
| GitHub Actions | Does it still run elsewhere? |
| Quarto | How are results communicated? |
renv and commit renv.locktargets for the main workflow| Pitfall | Better practice |
|---|---|
| One giant script | Small functions plus a pipeline |
| Manual intermediate files | Define outputs as named targets |
| Untracked package versions | Commit renv.lock |
| CI installs the latest packages | Restore from renv lockfile |
| Reports do hidden analysis | Reports consume pipeline outputs |
https://github.com/lucy-dwr/reproducible-r-workflow-demo
_targets.R — each target is an analysis product.targets::tar_visnetwork()targets::tar_make()targets::tar_outdated()targets::tar_make() again — only affected targets rebuild.targets makes the analysis workflow explicitrenv records the software environmentThe goal is not to make analyses more complicated. The goal is to make the complexity visible, testable, and easier to maintain.
Reproducible R workflows