Overview

Quartz 4 builds Markdown to public/, and a GitHub Actions workflow publishes that folder to GitHub Pages. These steps target Quartz 4 (quartz.config.ts). Upstream’s default branch is now Quartz 5, which uses quartz.config.yaml and npx quartz plugin install --from-config, so clone the v4 branch explicitly.

Prerequisites

  • Node 22 or newer and npm 10.9.2 or newer (the engines floor in Quartz 4’s package.json).
  • A GitHub repo you can enable Pages on, and a domain whose DNS you control.

Steps

1. Clone Quartz 4 and install

git clone -b v4 https://github.com/jackyzha0/quartz.git mysite
cd mysite && npm ci
git remote set-url origin git@github.com:<you>/<repo>.git
git branch -M main && git push -u origin main

The clone’s local branch is v4; renaming it to main matches the workflow trigger below. See run-a-quartz-static-site-locally to preview first.

2. Set baseUrl

In quartz.config.ts, set baseUrl to the bare domain: no protocol, no path. The sitemap, RSS feed, and canonical URLs are built from it. See quartz-config.

configuration: { pageTitle: "My Site", baseUrl: "yourdomain.com" }

Without a custom domain, a project repo is served under a subpath, so include it: baseUrl: "<user>.github.io/<repo>".

3. Add the workflow

This is the core of this repo’s .github/workflows/deploy.yml, minus its lint gates.

name: Deploy to GitHub Pages
on:
  push:
    branches: [main]
permissions:
  contents: read
  pages: write
  id-token: write
concurrency:
  group: pages
  cancel-in-progress: true
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v7
        with: { fetch-depth: 0 }
      - uses: actions/setup-node@v7
        with: { node-version: 22 }
      - run: npm ci
      - run: npx quartz build
      - uses: actions/upload-pages-artifact@v5
        with: { path: public }
  deploy:
    needs: build
    runs-on: ubuntu-latest
    environment:
      name: github-pages
      url: ${{ steps.deployment.outputs.page_url }}
    steps:
      - id: deployment
        uses: actions/deploy-pages@v5

Use fetch-depth: 0 so Quartz can read git history for dates. pages: write and id-token: write are both required; without id-token: write, deploy-pages fails with a 403.

4. Enable Pages with the Actions source

Open Settings, Pages, and set Source to GitHub Actions. Do not pick “Deploy from a branch”. Push to main and confirm both jobs go green. If deploy is rejected by environment protection rules, delete the existing github-pages environment under Settings, Environments; the next run recreates it.

5. Attach the domain

Follow point-a-custom-domain-at-github-pages for the DNS records, verification, and HTTPS.

Verify it worked

dig +short yourdomain.com          # four 185.199.x.153 addresses
curl -sI https://yourdomain.com | head -1   # HTTP/2 200

Common errors

  • A custom workflow ignores any CNAME file; the domain is stored in Settings, Pages. Plugin.CNAME() still writes public/CNAME, which is harmless. If the domain “unsets itself”, re-enter it in Settings.
  • Old links ending in / 404 on non-folder pages. Quartz emits page.html files and GitHub Pages does not redirect trailing-slash URLs to them; Cloudflare is the alternative host if existing links matter (deploy-a-static-site-to-cloudflare-pages).
  • Dates are all the build date. The checkout was shallow; keep fetch-depth: 0.

FAQ

Which Quartz branch should I clone for GitHub Pages?

Clone the v4 branch explicitly. Upstream’s default branch is now Quartz 5, which uses quartz.config.yaml instead of quartz.config.ts.

Why does deploy-pages fail with a 403?

The workflow is missing id-token: write. Both pages: write and id-token: write are required.

Why do all my Quartz page dates show the build date?

The checkout was shallow. Keep fetch-depth: 0 so Quartz can read git history for dates.

Does GitHub Pages use the CNAME file Quartz generates?

No. A custom Actions workflow ignores any CNAME file, and the domain is stored in Settings, Pages; re-enter it there if it unsets itself.

Quartz emits page.html files and GitHub Pages does not redirect trailing-slash URLs to them. Cloudflare is the alternative host if existing links matter.