From Quartz to Zola, bypassing Hugo

I just transferred my knowledge base over to Zola. The starting point was Karpathy’s knowledge base post from April 2, 2026. Initially I built locally and viewed with Obsidian. Wanting a public view, I used Quartz which was very easy to set up. I started looking for alternatives when builds took over 4 minutes and 3 GB memory on 1000+ pages.

I chose Zola as a clean minimal alternative to Hugo. Zola and Hugo had equivalent build times in testing. Only Zola has native backlink tracking. And PR#3116 has wikilinks support. To extend Hugo, I considered writing a separate compatibility layer in Rust. Since Zola is written in Rust, I can extend it directly. Also the community feels like something I can contribute to, since the PR states they’re looking for testers.

I started on the next branch, merged PR#3116, and added a few things along the way, all of which went quite smoothly. What worked well, what did I change, and what did I add?

What went well

  • All of my existing tags, and a few obvious improvements, fit well under the taxonomy system
  • Customizing the theme to my liking was super easy
  • Cloudflare deployment was a snap

What I tweaked

  • Disambiguation suggestions when a duplicate is found (I have 3)
  • Let wikilinks point to aliases and allowlisted missing pages
  • Allow markdown to render hard breaks, for single-line transcripts (optional)

What I added

  • Self-fragment links such as [[#details]]
  • Ability to link to colocated assets and taxonomy terms
  • Relative paths like [[./sibling]] and [[../parent]]
  • Opt-in asset allowlisting and output-size limits

Non-static stuff

I also moved away from Quartz’s FlexSearch static search, to avoid a 6.3 MiB index (decoded to 18.21 MiB). I switched to D1 FTS5 search on the same Cloudflare worker that serves the site. It’s about twice as accurate and fast. I got Zola to build the JSONL search corpus in a second pass over its already-rendered article HTML. This could probably be folded into the rendering pipeline as a single pass.

Nice! I’ve replied on the wikilinks PR for the link related parts.

I didn’t know this was a pulldown-cmark option, I think we can expose it.

Any other issues with Zola or Tera?

1 Like

Other than the cachebust issue you already fixed, Tera has been smooth. The only real gap I found is around internal/alias.html. A site-level override works and I’m using one. But the source says it isn’t overridable and I couldn’t find that behavior documented. It might be worth making the override contract explicit and testing it.

:thinking: it’s probably years old if you go past the tera2 changes, not entirely sure.

It’s working now because of tera2 fallback prefixes, I don’t think anyone has wanted to override that one before? What are you changing?

I was overriding internal/alias.html because my build turns the generated aliases into Cloudflare _redirects, and the generator was reading a canonical tag to get the destination. The canonical could also provide an extra signal to crawlers when the HTML fallback is served. Note google saying “these methods can stack and thus become more effective when combined” here.

But the existing meta refresh contains the same destination, so I changed the generator to read that and removed the override. Note the “not overridable” comment no longer matches the Tera2 behavior.

Thanks for sharing, I’m building my pkm (Christopher’s Digital Cellar) with Quartz at the moment, and it’s fine for what I want now, but definitely feel Zola’s more capable. Quartz does have slow build times and customization is harder than it should be except for trivial things like colors. Modifying that footer at the bottom for example or the 404 page. I build my main site with Zola (Christopher’s Digital Hall), and it was a good experience, even moving to Tera 2 wasn’t that bad.

One thing I like about Quartz is that digital graph. Anyway to replicate that in Zola?

Thanks for this post, I’m bookmarking it for when/if I want to move out of Quartz.