Overview

Most Quartz build problems are quiet: the build exits 0 and the output is wrong, with a missing page, a link to the wrong target, or an unexpected date. --verbose shows what each stage did to each file. This page lists the signals to read and the checks that catch what the build does not report.

Run --verbose first

--verbose (alias -v) prints one line per file per stage.

npx quartz build --verbose 2>&1 | tee build.log
  • Loaded N plugins followed by the transformer, filter, and emitter names in order. Plugin names are what you grep for; CrawlLinks appears as LinkProcessing.
  • [markdown] content/foo.md -> foo (12ms): the slug Quartz derived from the path.
  • [filter:RemoveDrafts] some/slug: that filter dropped the page. This explains a page that vanished.
  • [emit:AliasRedirects] old/slug.html: which emitter wrote which file.
  • Failed to process markdown with a stack trace: a transformer threw on that file, usually malformed frontmatter YAML.

With markdownLinkResolution: "shortest", a bare [[quartz]] resolves only when exactly one page has that filename. If two pages share it, Quartz treats the target as a path from the content root and emits a link that 404s, with no warning. Use the folder-prefixed form, [[tooling/quartz]].

Quartz has no link checker, so CI must supply one; this repo runs scripts/lint-links.mjs. The ObsidianFlavoredMarkdown option disableBrokenWikilinks: true renders unresolved links as <a class="internal broken">, but it compares the link text with full slugs, so bare-slug links count as broken even when shortest would resolve them. Enable it only on a vault that uses folder-prefixed links everywhere.

Aliases join the slug list, so an alias that collides with a real filename can make a bare link ambiguous.

Audit frontmatter that degrades silently

A page with incomplete frontmatter still builds.

  • No title: the filename stem becomes the title.
  • An unparseable date: a warning is logged and the date becomes the build time, so the page looks freshly edited.
  • A slug: field is ignored. The output path always comes from the file path, so keep the field and filename aligned with a lint.
  • status: draft does not hide a page; only draft: true does (quartz-plugins).
grep -rL "^title:" content/ --include="*.md"

Treat quartz/.quartz-cache/ as disposable

The directory holds esbuild output (transpiled-build.mjs, transpiled-worker.mjs) and cached fonts for OG images. Quartz regenerates the transpiled files on each build, so deleting the directory is safe and rarely the fix. Keep it in .gitignore.

rm -rf quartz/.quartz-cache && npx quartz build

Diagnose theme problems from the CSS variables

  1. A wrong or missing color: in DevTools, check that the variable (var(--secondary)) resolves. Colors come from the theme.colors object (quartz-config).
  2. Fonts blocked by a Content Security Policy: this happens with cdnCaching: true, which links to Google Fonts at runtime. Set cdnCaching: false to self-host the fonts, or fontOrigin: "local" and write your own @font-face.
  3. A component that looks right in light mode and wrong in dark mode: its .css uses hex values instead of theme variables (quartz-components).

Verify public/ before pushing

The build empties public/ first, then writes only what emitters produce.

cat public/CNAME                          # bare custom domain
ls public/sitemap.xml public/index.xml    # sitemap and RSS
ls public/static/contentIndex.json        # search index
find public -name "*.html" | wc -l        # a sudden drop means a filter or ignore pattern

Per-page OG images come from a worker pool and can finish after the main build prints “Done”, so count them only after it flushes.

Recover a broken build

  1. rm -rf quartz/.quartz-cache.
  2. npm ci.
  3. node -v; Quartz 4.5.2 needs Node 22 or newer.
  4. Rerun with --verbose into a log and read the first stack trace.