Building a Personal Website with Quarto

Quarto
website
How I rebuilt my personal website using Quarto - project structure, blog setup, and deployment to GitHub Pages.
Author

Marina Varfolomeeva

Published

May 31, 2026

For many years I maintained neglected a Hugo-based personal page using Academic framework (which is now became HugoBlox). It looked pretty-ish, but it was too complex to maintain and the framework was updated too often. It took some discipline to keep publication list up to date, and the only reason I kept the site alive was the list of courses I taught. But I never got around to writing blog posts, and the site felt more like a static CV than a dynamic hub for my work. Then I changed jobs and moved to a new country and stopped maintaining the site at all.

This time I wanted something simpler, so I rebuilt the site from scratch using Quarto. The main reason for this choice is that Quarto handles both R and Python natively — no plugins, no workarounds.

Initial setup

Creating a new Quarto website project:

quarto create project website .

This generates a minimal _quarto.yml and index.qmd. I configured the output directory, navigation, theme, and execution settings:

_quarto.yml
project:
  type: website
  output-dir: docs

website:
  title: "User Name"
  navbar:
    left:
      - href: index.qmd
        text: About me
      - href: blog/index.qmd
        text: Blog

format:
  html:
    theme: lightly

execute:
  freeze: auto

Live preview while editing:

quarto preview

Project structure

Top-level pages (index.qmd, publications.qmd, teaching.qmd) live at the root; blog posts each get their own directory under blog/:

blog/
  2025-01-10-my-post/
    index.qmd
    data/

The publications and teaching pages are driven by YAML data files rendered through EJS templates, which keeps the content separate from the layout.

Blog with R and Python

Blog posts are plain .qmd files with a short YAML header:

---
title: "Post Title"
date: "2025-01-10"
categories: [R, Statistics]
---

Quarto runs R chunks via knitr and Python chunks via Jupyter. The key setting that makes this practical is freeze: auto in _quarto.yml — code is only re-executed when the source file changes, so a Python post doesn’t re-run every time I touch a page written in R.

Maybe I will have to rethink this approach if I actually start writing more, but for now it works.

Deployment

The site is deployed to GitHub Pages using quarto publish gh-pages, which renders the project and force-pushes the output to a gh-pages branch. Source code lives in a separate private repository, so the public varmara/varmara.github.io repo contains only rendered HTML.

Setting up the remotes:

git init
git remote add origin git@github.com:username/username.github.io.git
git remote add src    git@github.com:username/username-src.git
git config branch.master.pushRemote src

Backing up source and publishing:

git add .
git commit -m "update"
git push                 # goes to private source repo
quarto publish gh-pages  # renders and pushes HTML to public repo

In the public repository settings: Pages → branch gh-pages, folder /.