Publishing a Quarto Site to GitHub Pages

Using GitHub Actions to easily publish your site
technology
programming
Author

Ian Taylor

Published

December 22, 2022

Quarto websites are a great way for people familiar with code notebooks like Rmarkdown and Jupyter to share their work on the internet. If you use GitHub for version control of your site’s code, then GitHub Pages is a natural and convenient way to publish your site. But because Quarto is relatively new, the methods for publishing on various platforms including GitHub Pages are still evolving. I wasn’t satisfied with the existing methods for publishing Quarto sites on GitHub pages, so I created my own.

Prerequisites

  • A Quarto site in a GitHub repository that can successfully be rendered and previewed on your local computer.

Existing methods for Quarto sites on GitHub Pages

The Quarto GitHub Pages documentation offers three methods of publishing your site on GitHub pages, but they each have disadvantages.

  1. Render to docs/ folder

With this method, you change the Quarto output directory to docs/, which is a directory GitHub Pages can serve content from. This is easy to set up, but it requires checking the rendered HTML pages into version control. Generally it’s frowned upon to have version control tracking content that can be regenerated from other source code in the repository, so I would like to avoid using this method.

  1. Use quarto publish gh-pages

Quarto includes its own publish command for many platforms including GitHub Pages. This method works by creating a branch in the repository called gh-pages which contains the rendered content. This method also has rendered content tracked in version control, although because it is in a separate branch, it can be committed only when you want. The gh-pages branch method is based on an old GitHub Pages publishing option. This branch is somewhat separate from the rest of the version control tree. Because the gh-pages branch is never intended to be merged back into the default branch, this feels too much like a hack to me and goes against the purpose of branches in version control.

  1. Use GitHub Actions

The Quarto documentation provides a GitHub Action (workflows which are run by GitHub upon certain conditions) to automatically publish the site when you push code to the GitHub reposiory. But this action just runs quarto publish gh-pages behind the scenes and so has all the problems of that method.

Improved method: a better GitHub Actions workflow

A better method that I am using is based on GitHub Actions, but doesn’t use the workflow provided by Quarto. Instead it’s based on a GitHub template workflow for publishing static content.

How to use

First, enable GitHub Pages in your repository by selecting GitHub Actions as the Source.

Activating GitHub Pages through GitHub Actions in repository settings

Next, set up Quarto’s freeze feature by editing _quarto.yml:

_quarto.yml
# ...
execute:
  freeze: auto
# ...

Finally, copy this code into the file .github/workflows/publish.yml in your repository (create it if it doesn’t exist):

.github/workflows/publish.yml
# Workflow for rendering and deploying quarto site to GitHub Pages
# Based on the GitHub example static content deploy action
name: Deploy Quarto site to Pages

on:
  # Runs on pushes targeting the default branch
  push:
    branches: ["main"]
  # Allows you to run this workflow manually from the Actions tab
  workflow_dispatch:

# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
permissions:
  contents: read
  pages: write
  id-token: write

# Allow one concurrent deployment
concurrency:
  group: "pages"
  cancel-in-progress: true

jobs:
  # Single deploy job since we're just deploying
  render-deploy:
    environment:
      name: github-pages
      url: ${{ steps.deployment.outputs.page_url }}
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v3
      
      - name: Set up Quarto
        uses: quarto-dev/quarto-actions/setup@v2

      - name: Render
        uses: quarto-dev/quarto-actions/render@v2
        
      - name: Setup Pages
        uses: actions/configure-pages@v2
        
      - name: Upload artifact
        uses: actions/upload-pages-artifact@v1
        with:
          # Upload quarto render output directory
          path: '_site'
          
      - name: Deploy to GitHub Pages
        id: deployment
        uses: actions/deploy-pages@v1

Now when you push to the default branch of your repository, this action will render your site using the frozen computations, bundle the rendered static HTML content, and deploy it to GitHub Pages. After the workflow runs, you can access the site at https://<your-username>.github.io/ if this is your user pages repository, or https://<your-username>.github.io/<repo-name> if this is any other repository.

Additional configuration

  1. If your default branch isn’t called “main”, change the on: options:
.github/workflows/publish.yml
# ...
on:
  # Runs on pushes targeting the default branch
  push:
    branches: ["your-default-branch"]    # <---- **CHANGE THIS LINE**
  # Allows you to run this workflow manually from the Actions tab
  workflow_dispatch:
# ...
  1. If your site renders to a folder other than _site, change the “Upload artifact” step accordingly:
.github/workflows/publish.yml
# ...
      - name: Upload artifact
        uses: actions/upload-pages-artifact@v1
        with:
          # Upload quarto render output directory
          path: 'your-render-output-path'    # <---- **CHANGE THIS LINE**
# ...
  1. If your Quarto site is not located in the root of your repository, for example if using quarto to create documentation for your code, add a path option to the “Render” step and also change the “Upload artifact” step option:
.github/workflows/publish.yml
# ...
      - name: Render
        uses: quarto-dev/quarto-actions/render@v2
        with:
          path: 'your-quarto-folder'    # <---- **CHANGE THIS LINE**
# ...
      - name: Upload artifact
        uses: actions/upload-pages-artifact@v1
        with:
          # Upload quarto render output directory
          path: 'your-quarto-folder/_site'    # <---- **CHANGE THIS LINE**
# ...

These changes can be combined if necessary.

How it works

This GitHub action works by rendering your site on the GitHub server (the “runner”), then packaging the resulting static content and deploying it on the GitHub Pages server. It doesn’t require write access to your repository. Because of the Quarto freeze option, the runner doesn’t need to have R, Python or any computational packages installed. The rendered content is exactly what you would have seen in a preview on your local computer.