Hello, Quarto. Bye, Zensical.

news
Migrating the site from Zensical to Quarto, and what it took to get it building on Cloudflare Pages.
Author

Victor S HUANG

Published

23 May 2026

Hello, Quarto. Bye, Zensical.

Hello, Quarto. Bye, Zensical.

This site used to run on Zensical. It now runs on Quarto.

Why move

Zensical is the spiritual successor to Material for MkDocs, from the same author. The direction is right. The execution is early. Plugin coverage is thin, theming hooks are still shifting, and the documentation lags the code. Fine for a landing page. Not where I want to spend cycles when I’m trying to publish.

Quarto sits in a different place. It is a scientific publishing system first and a static site generator second. That ordering matters. .qmd and .ipynb are first-class inputs. Code executes at render time and the outputs are pinned via freeze. Math, citations, cross-references, and figure numbering are part of the format, not bolted on. The same source renders to HTML, PDF, and reveal.js without a second toolchain.

For a site that will mix prose with notebooks and blog posts, that is the whole game.

The migration

Content was straightforward. Markdown is markdown. Front matter shifted from MkDocs conventions to Quarto’s:

---
title: "Hello, Quarto. Bye, Zensical."
date: "2026-05-23"
categories: [news]
---

The blog index is a Quarto listing page. No plugin, no template hacking:

---
title: "Blog"
listing:
  contents: posts
  sort: "date desc"
  type: default
  categories: true
  feed: true
---

Theming is Bootstrap plus SCSS overrides. I kept Litera and added a styles-dark.scss for dark mode tweaks. Highlight styles are split per scheme so code blocks read well in both:

format:
  html:
    theme:
      light: litera
      dark: [litera, styles-dark.scss]
    highlight-style:
      light: github
      dark: monokai

Cloudflare Pages

This is the part that needed care. Cloudflare Pages does not ship Quarto in its build image. The official path is to install it yourself in the build step.

I pin the version. Floating versions are a great way to wake up to a broken site:

#!/usr/bin/env bash
set -euo pipefail

QUARTO_VERSION="${QUARTO_VERSION:-1.9.37}"

curl -fsSL "https://github.com/quarto-dev/quarto-cli/releases/download/v${QUARTO_VERSION}/quarto-${QUARTO_VERSION}-linux-amd64.tar.gz" \
  | tar -xz -C /opt
export PATH="/opt/quarto-${QUARTO_VERSION}/bin:${PATH}"

quarto render

In the Pages project settings:

  • Build command: ./build.sh
  • Build output directory: _site
  • Root directory: project root

A few things worth knowing if you walk this path:

Pin the Quarto version explicitly. Quarto’s HTML output evolves between minor releases. The inline theme-toggle script in particular references DOM nodes that older versions did not emit. If your build image and your local version drift, you can ship a site whose JavaScript throws on load and silently falls back to defaults. Ask me how I know.

Commit _freeze/. Cloudflare’s builders are ephemeral and do not have your Python or R environment. Freezing computational output locally and checking it in means the builder only needs Quarto and pandoc, not your full data stack. Build times drop to seconds.

Skip output-dir surprises. Quarto writes to _site by default. Match Cloudflare’s output directory to that and resist the urge to rename.

Back to top