🚀🤖 R Users: Supercharge your work with GitHub Actions for R
This post is based off a presentation I made for the 2025 Cascadia R conference.
Github for many years was the place to store and share code, but it’s now a place to run code. And it’s my favorite place to run R code.
I’ve always struggled to get things off my laptop and deployed into the world for people to use. Especially things like R. Github Actions is a great way to break down those barriers and get your code out into the world where it belongs.
🤖 Contents #
- What is a Github Action?
- How do Github Actions work?
- The Anatomy of an Action
- Example of a Github Action
- Resources for learning Github Actions
What is a Github Action? #
In a few words - a Github Action is a great way to automatically run code. More specically, code runs in the cloud using Github’s servers - typically Linux virtual machines on Microsoft Azure.
But they’re simple enough that anyone can spin one up and run it for free.
What can you use Github Actions for? #
Anything and everything. You can use Github Actions to run just about anything that R can currently do.
- Keep analysis current with regularly updating data 📊
- Website builds 🏗️
- Package development 📦
- Ongoing testing, QA 🧪
- Rmarkdown or Quarto reports
- Social Media or email bots
My first few Github Actions were to create twitter and Bluesky bots.
PFDBOT sends out a post every hour of one stock holding that the Alaska Permanent fund, the 80+billion dollar soverign wealth fund. The code picks one random stock from a spreadsheet, creates a post, and sends it through the Bluesky API, via bskyr package.

AlaskaCameras pulls in a view from one of the highway cameras, which captures incredible beauty, as well as road surfaces. Github Actions runs your code while you sleep.

How actions work (conceptually) #
Github Actions are super flexible and powerful - but you must be very specific in telling it when and how to run. But at a broad level, the workflow is not all that different than the manual process of running some code. The concept looks like this:
- Tell the code when it should run.
- Start up a virtual machine
- Install R
- Install all packages you need to run your code
- Run your code
Source: David Keyes’ R For the Rest of Us
Anatomy of a Github Action #
You can go exceedingly deep into using Github Actions for advanced software development. But for basic task like running an R script or generating a Quarto report, the major parts are laid out here:
Workflow 📝 #
You need a workflow to create your action. The workflow file is a YAML text document that lays out the who, what, when, and how of the action.
Events 📅 #
What triggers the steps. You need to tell the code when to run. The two main families of events are code related events, such as when a pull request is created or new code is pushed up to the repository. The second group is more custom - like a scheduled cron job or through the Github API.
Jobs 💼 #
Your worflow will have at least one job - this creates the virtual machine and will include one or many steps. THe default is a linux, such as ubuntu-latest.
Steps 🚀 #
Steps is where the works is done. A series of steps install software, extra packages, and can execute the code.
Example of a Github Action for R #
I live in Anchorage, Alaska and we’ve had two of the wildest winters in memory in last coouple years. I wanted an automated report that pulls in the latest snowfall data, compares it to historic seasons, and creates a report with some visualizations. Perfect use case for Github Actions.
Here’s the final results look like published online.

It hits an NOAA data API for the latest snow each day and reads in a few CSV files of historic data, going back 73 years to 1952.
The workflow file is where all of the configuration happens. Here it is in its entirety, but I’ll walk through it all here.
name: snowfall_report
on:
schedule:
- cron: "0 0 * * *"
workflow_dispatch:
jobs:
create_report:
runs-on: ubuntu-latest
env:
WXTOKEN: ${{ secrets.WXTOKEN }}
steps:
- uses: actions/checkout@v4
- uses: r-lib/actions/setup-r@v2
with:
r-version: '4.5.0'
- uses: quarto-dev/quarto-actions/setup@v2
with:
version: 1.4.515
- uses: r-lib/actions/setup-r-dependencies@v2
with:
cache-version: 1
- uses: quarto-dev/quarto-actions/render@v2
with:
to: html
- name: Commit Data
run: |
git config --local user.email "actions@github.com"
git config --local user.name "GitHub Actions"
git add snowfall.html
git commit -m "snowfall" || echo "No changes to commit"
git push origin || echo "No changes to commit"-
First, you’ll want to create a repository on Github for your files. I have a repo called snowfall_report on Github.
Here I have the files for the analysis and reporting, the description file for packages I want to install, and the _quarto.yaml file for the Quarto project.
To define the action, you go to the Actions tab on top and there you can create the workflow file right in the browser. This one is called snow_report_action.yml.

Workflow 📝 #
You need a workflow to create your action. The workflow file is a YAML text document that lays out the who, what, when, and how of the action.
Events 📅 #
What triggers the steps.
name: snowfall_report
on:
schedule:
- cron: "0 0 * * *"
workflow_dispatch:
Jobs 💼 #
We create a job called “create_report” and set it to run on ubuntu-latest. This Linux virtual machine is a good default, but you can choose MacOS or Windows if you have a specific reason to. (They burn through your free minutes faster than the Linux does.) We also add a secret to the job. I’ll get into this later.
jobs:
create_report:
runs-on: ubuntu-latest
env:
WXTOKEN: ${{ secrets.WXTOKEN }}
Steps 🚀 #
Steps is where the real work happens. The uses steps actually bring in actions from another repository, and those will do the large majority of the work in this case. Ones you define yourself will look much more like a bash command.
steps:
- uses: actions/checkout@v4
- uses: r-lib/actions/setup-r@v2
with:
r-version: '4.5.0'
- uses: r-lib/actions/setup-r-dependencies@v2
with:
cache-version: 1
- uses: quarto-dev/quarto-actions/setup@v2
with:
version: 1.4.515
- uses: quarto-dev/quarto-actions/render@v2
with:
to: html
- name: Commit Data
run: |
git config --local user.email "actions@github.com"
git config --local user.name "GitHub Actions"
git add snowfall.html
git commit -m "snowfall" || echo "No changes to commit"
git push origin || echo "No changes to commit"-
The first actions/checkout gives the action access to the code in the repo - it will need to use the quarto file and the CSVs, etc.
Next r-lib/actions/setup-r@v2 brings in an action that has been helpfully set up by R maintainers. You’ll want to get familiar with a couple of these R Actions. I specific the version as well.
And we’ll need some packages. the r-lib/actions/setup-r-dependencies@v2 will install all of the packages I have listed in the description file. It also will cache them so I don’t need to install fresh from CRAN every time.
Almost there. Two Quarto related steps are next. quarto-dev/quarto-actions/setup@v2 and quarto-dev/quarto-actions/render@v2 will install Quarto and then render a Quarto project if there is one in the repo.
That will generate an HTML file of the report output. I want to serve this live on the internet, so I will want to push that html file to my repository. The final step Commit Data will add that to the repo.
Failure is definitely an option. #
One side effect of working with actions is you become more resilient to constant and unrelenting failure. Your action may not work the first time. But you can look in the logs to find an error message and start troubleshooting.

First, click on a workflow within your action tab - there will be a list of runs that have occured. Click on a run that failed to find the error. You’ll then see a list of all the steps and you can dig into the one where the error happened.

And finally drill down into the details and see the error that hopefully makes some sense.


🕵️🤐 Secrets #
Github is a pretty public place, and the logs are indeed public too. What if you need to use an API key in your action or use login credientials? or something?
You can keep those confidential by using repository secrets You are able to securely store an API key or similar in the github. and then you’re able to fetch it.
In R, that looks like.
wxToken <- Sys.getenv("WXTOKEN")
I can then use the weather API key securely.
And because github action logs are public - you want to be sure to never print it out. But Github has all sorts of way that it will suppress them if you ever try to print them out. and you can be sure - I have tried.
To create one, you can do that in your repo options.

You give it a name and a value.

Favorite Resources #
Here’s how I learned how to make Github Actions and a great spot to start.