How to render Quarto websites faster

Author

Luke

Published

February 8, 2025

Today a quick hack for pushing website updates.


For this Quarto website, I basically have my _quarto.yml set up such that rendering my .qmd documents to HTML will store the HTML files in a specific directory. In this case, the directory is _site.


project:
  type: website
  output-dir: _site


I then have a bash script that will push the files in this folder only to the repository that hosts the website, and push all source files to my public website code repository. This is fairly convenient since I just run the script to update the website. However, as my website started to have more and more pages, I realized that using quarto render indiscriminately really slows down the process.

So it dawned upon me the other day that I could simply only render the files that have changed. Conveniently, git already tracks file changes, meaning I could use some git commands to figure out which files to render.

This was surprisingly easy to achieve. Here’s the essential part:


# Get list of changed .qmd or .md files in git working tree
CHANGED_FILES=$(git status --porcelain --untracked-files=no | awk '{print $2}' | grep -E '\.qmd$|\.md$')

if [ -z "$CHANGED_FILES" ]; then
    echo "No changed Quarto files to render"
    exit 0
fi

echo "Rendering changed files:"
echo "$CHANGED_FILES"

# Render changed files
quarto render $CHANGED_FILES


The first line simply generates a machine-readable list of changed .qmd (and .md) files in the git working tree. Then there’s an if clause and some print statements. Finally, identified files are rendered. Dead simple!

This is super convenient and speeds up the process of updating my website by a factor of 100 or so.

In case you’re interested, here’s the full bash script I use (at the time of writing):


#!/bin/bash

git add .

# Get list of changed .qmd or .md files in git working tree
CHANGED_FILES=$(git status --porcelain --untracked-files=no | awk '{print $2}' | grep -E '\.qmd$|\.md$')

if [ -z "$CHANGED_FILES" ]; then
    echo "No changed Quarto files to render"
    exit 0
fi

echo "Rendering changed files:"
echo "$CHANGED_FILES"

# Render changed files
quarto render $CHANGED_FILES

# Prompt for a commit message
echo "Enter a commit message:"
read commit_message

# --- Push source files to the main repository (lukmayer/website.git) ---

# Ensure the current directory is your main project directory (not _site)
# Add and commit changes to the source repo

git commit -m "$commit_message"

git remote add origin git@github.com:lukmayer/website.git

# Push changes to the main repository (lukmayer/website.git)
# Ensure 'origin' points to the source repo (lukmayer/website.git)
git push -f origin master 


# --- Push rendered files to the GitHub Pages repository (lukmayer.github.io.git) ---

# Navigate to the _site directory (contains the rendered files)
cd _site

# Initialize a new Git repository inside _site if it doesn't exist already
if [ ! -d ".git" ]; then
    git init
    git remote add origin git@github.com:lukmayer/lukmayer.github.io.git
else
    git remote set-url origin git@github.com:lukmayer/lukmayer.github.io.git
fi

# Add and commit the rendered site files
git add .
git commit -m "$commit_message"

# Force push the rendered files to the gh-pages branch of the GitHub Pages repo
git push -f origin master:gh-pages  # Ensure that 'gh-pages' is the correct branch for GitHub Pages

# Navigate back to the root directory of the project
cd ..


If you use this script, make sure to give it execute permissions with chmod +x update.sh1 and run it with ./update.sh. Enjoy! :)

1 Always make sure you know what shell commands do before doing this!

Back to top