Overview
Cloudflare Pages is a zero-config CDN-backed host that gives Quartz better global latency than GitHub Pages and free analytics via Cloudflare Web Analytics. This guide forks Quartz, connects the repo to Cloudflare Pages, configures baseUrl, and wires a custom domain. It takes under 30 minutes on a fresh Cloudflare account. Compare the trade-offs in vercel-vs-cloudflare.
Prerequisites
- A Cloudflare account. Free tier is enough for a content site.
- A GitHub account. Cloudflare Pages deploys from GitHub or GitLab.
- Node 22 installed locally. Check with
node -v. - A custom domain whose DNS is on Cloudflare (or that you can transfer). See namecheap-dns if the domain is on Namecheap.
- Local Quartz running. See run-a-quartz-static-site-locally if not.
Steps
1. Fork Quartz and push your content
git clone https://github.com/jackyzha0/quartz.git mysite
cd mysite
npm ciDrop your markdown into content/. Every page needs YAML frontmatter with at minimum title, slug, category, and status. See quartz for the full plugin set.
Push the repo to your own GitHub account, default branch main.
2. Set baseUrl in quartz.config.ts
Edit quartz.config.ts. Set baseUrl to the bare domain with no protocol and no trailing slash.
configuration: {
pageTitle: "My Site",
baseUrl: "yourdomain.com",
// ...
}Remove Plugin.CNAME() from the emitters list. That plugin is specific to GitHub Pages and not needed here. Cloudflare Pages handles the custom domain at the CDN layer.
3. Build locally and confirm no errors
npx quartz build
# should print "Done processing X files" with no errorsCommit everything and push to main.
4. Connect Cloudflare Pages
- In the Cloudflare dashboard, open Pages, then click “Create a project.”
- Select “Connect to Git” and authorize the GitHub app.
- Pick your repository.
- On the “Set up builds and deployments” screen:
- Framework preset: None (Quartz is not in the preset list).
- Build command:
npm ci && npx quartz build - Build output directory:
public - Node version:
22(set under Environment Variables asNODE_VERSION=22).
- Click “Save and Deploy.”
Cloudflare runs the first build. Check the build log under “Deployments” and confirm the last line is “Deployment complete.”
5. Set the custom domain
In your Cloudflare Pages project, open Settings, then Custom Domains. Click “Set up a custom domain” and enter yourdomain.com.
If the domain’s DNS is already on Cloudflare, the CNAME is added automatically. If not, Cloudflare shows the CNAME record to add at your registrar. Wait for DNS propagation (usually under five minutes when already on Cloudflare), then click “Activate domain.”
Cloudflare Pages provisions a Let’s Encrypt certificate automatically. HTTPS is enforced by default.
6. Set SSL/TLS mode to Full (strict)
In the Cloudflare dashboard, go to your domain, then SSL/TLS, then Overview. Set the mode to “Full (strict).” This ensures the connection between Cloudflare and the origin is also verified. See cloudflare for the full TLS configuration playbook.
7. Confirm the deployment URL
Cloudflare Pages assigns a preview URL like mysite.pages.dev. This URL stays live for all deployments and is useful for testing PRs. Add it to your quartz.config.ts baseUrl only if the custom domain fails DNS verification; otherwise keep the custom domain as baseUrl.
Verify it worked
# 1. HTTPS responds with 200
curl -sI https://yourdomain.com | head -1
# expected: HTTP/2 200
# 2. The build output directory is correct
curl -s https://yourdomain.com | grep -c "<html"
# expected: 1
# 3. No mixed-content warnings (check the browser console after loading the page)
# 4. Cloudflare caches the response
curl -sI https://yourdomain.com | grep cf-cache-status
# expected: cf-cache-status: HIT (on second request)Common errors
- Build fails with “node: not found.” Set
NODE_VERSION=22in the Pages project’s Environment Variables section. baseUrlmismatch causes broken links. ConfirmbaseUrlis the bare domain withouthttps://or a trailing slash.Plugin.CNAME()writes aCNAMEfile that causes 404s on Cloudflare. Remove it from the emitters list; it is only needed for GitHub Pages.- Custom domain stuck on “Pending.” The CNAME was added but DNS has not propagated. Use
dig CNAME yourdomain.comto confirm, then wait up to 30 minutes. - Pages project builds from the wrong branch. In Settings, Builds and deployments, confirm “Production branch” is set to
main.