Migrating to Quarto

Some thoughts on the process of migrating this website to Quarto

Darius A. Görgen


August 30, 2022

I recently migrated this very website that you are seeing to the Quarto engine. With this post, I want to share some of my experiences of the migration process as well as some general thoughts on website generation with Quarto. To start with, it has really been a fun experience to set up this website using Quarto. Even though the tool is quite new and has only been publicly announced at rstudio::conf(2022) some time ago, it really is thoughtfully engineered, feature rich and easy to use.

To set up my motivation to migrate to Quarto, let me give you some insights of how I created content for my website before. I have been using the quite familiar Indigo theme base on Jekyll for some time. I liked it very much for its minimalist look and feel. However, creating content and get it “out there” was not quite a minimalist experience for me. Partly, that was due to my desire to feature both, content on R and Python, and very likely also due to my inexperience with websites more general. In order for you to get the picture, let me first explain how I created content using Jekyll and then what changed for me now that I am using Quarto.

The tidious way to create content…

In my previous set up using Jekyll I had a _drafts directory. There I would write some R Markdown files drafting my posts. Thanks to the awesome {reticulate} package I could already use Python in these R Markdown files using a virtual environment. I would add the following yaml header to all drafts:

   keep_md: true

That would tell the knitr engine to create both, a .html and a .md file. The files would all be rendered within the _drafts directory. I then would have to manually create another <post>-header.md file including the header information for the post I was currently working on, but nothing else:

title: "Some title"
description: "Some more description"
layout: post
date: 2020-05-10 10:00
 - msg
 - gtiff
 - python
headerImage: false
hidden: false # don't count this post in blog pagination
category: blog or project?
author: darius

The template repository that I was using thankfully included a bash file that would then allow me to select the name of a draft post. This script would take the .md that was outputted by {knitr}, add the yaml header that I created and then copy this new file over to the _posts directory from where the website would be available once checked out to GitHub. Referring to assets that should show up in a post was tedious and more than once error-prone. As you can imagine, I was very much keen to use an alternative, simpler way to handle my website. Entrance Quarto!

Designing a website with Quarto

The general directory structure of my Quarto website (restricted here to the most important parts) is actually quite simple:

├── contents
      ├── blog
      └──  projects
├── _quarto.yaml
├── index.qmd
├── renv
└── pyenv

I structure my contents into a blog and some information snippets about projects I have been working on. Each of those contain single directories for each post. Within a post directory, I include an index.qmd file and all assets that are to be referenced by this post. Note, that within the .qmd I can use R or Python at ease. When rendering, Quarto will automatically activate the virtual environment pyenv for Python code or the renv for R files (more on that later). The main landing page is index.qmd thus it is found in the top-level of the repository. Website-wide configurations, like the navbar, are included in _quarto.yaml. It is there that I specified to freeze the rendering of posts. That way quarto will only try to re-render posts if it finds changes in the source code. If that is not the case, the previous outputs will simply be copied to the _site directory where the rendered website is found. This is a very useful behavior, especially over long-time frames when package version changes might make it difficult to re-render older posts.

Within each .qmd, I now include the yaml header that I had to create manually before. So instead of actually 4 different files that I created to publish a single post that was then copied to the right location, I now use a single-source-of-truth, if you will, that is automatically rendered if needed once I issue quarto render to the command line. This really is a significant improvement of my personal workflow to put out new content! The source repository is also much cleaner and easier to argue about and troubleshoot if something goes wrong.

Seamless integration of Python and R in the same project

I am amazed by the seamless integration of both Python and R into a single project. For the R side, I am using {renv} for the housekeeping of packages. For Python I simply created a virtual environment via python3 -m venv pyenv to create a virtual environment within the project directory. Quarto will automatically activate this environment when executing Python code. I (or others) can even set up the project easily on a different machine by updating the requirements.txt every once in a while by using python3 -m pip freeze > requirements.txt. I mentioned earlier, that the freeze option is a useful feature over long time periods. It is also a very useful when collaboration with others on a website potentially using R and Python. Every contributor might only make small changes to single parts of the website. Using the freeze options ensures that the website as a whole stays intact, even for different language or version requirements between the posts.

Publishing with Quarto

My first idea to publish the website was using GitHub Actions to automatically build the site once changes to the main branch are checked out. While in principal this is possible, this approach has two major drawbacks. First, when version requirements are different between some posts this approach will fail when trying to set up the environment on GitHub Actions. This could be mitigated by ensuring that all posts are kept up-to-date with package developments, but maintaining this website should not be a full-time job. Second, setting up both the R and Python environment on GitHub actions takes quite some time and I would not like to wait about 30 minutes between checking out some changes and the deployment of the website. I briefly was thinking about changing the OS of the workflow to MacOS or Windows, hoping that using binaries would speed up the process. However, Quarto comes with a very nice feature which allows me to directly publish to the gh-pages branch from my local machine. Once I am satisfied with my changes I first checkout to the main branch. Then I issue quarto publish gh-pages and because of the freeze option being enabled, this quickly pushes the website to GitHub where it is then deployed. This actually saves some significant computation times on GitHub servers reducing the carbon footprint of this website.

Round up

Setting up a website using Quarto and customizing it has been a very fun experience. The design of the tool is very user-friendly and it helped me to improve the way I publish on this website. The freeze option is potentially saving an incredible amount of headaches for both single contributors who have to maintain state over longer periods of time and collaborators potentially using different programming languages. Posit (formerly known as RStudio) truly advances the way how we can work in multi-lingual projects and reduces the overhead associated with sharing content. I have been a great fan of R Markdown over the last couple of years. R Markdown has grown for over 10 years now. Quarto is meant to be its successor and I can’t wait to see what else will be possible with it over the next 10 years!