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
enginesfloor in Quartz 4’spackage.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 mainThe 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@v5Use 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 200Common errors
- A custom workflow ignores any
CNAMEfile; the domain is stored in Settings, Pages.Plugin.CNAME()still writespublic/CNAME, which is harmless. If the domain “unsets itself”, re-enter it in Settings. - Old links ending in
/404 on non-folder pages. Quartz emitspage.htmlfiles 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.
Why do old links ending in a slash 404 on GitHub 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.