foliate

2026-03-10 → 2026-07-30

A minimal static site generator that turns a markdown vault (e.g., Obsidian notes) into a static HTML website.

Why#

I’ve been keeping a collection of markdown notes that include research ideas, paper summaries, reading notes, how-tos, or blog-like posts (whatever you call it—a wiki, Zettelkasten, hypercard, … see Ideas of connected ideas). This works as a central place for my personal knowledge.

At the same time, I have been managing my homepage using Jekyll and GitHub Pages. This is a fine solution, but there has always been this nagging friction. It arises when I try to publish some of my pages in my wiki: should I copy the file to my homepage and publish as blog? But then this creates duplicates. Do I create a totally separate wiki site just for these? I did that, but it’s annoying to manage two totally separate system as my “homepage”.

So I always wanted to have a more integrated solution for this issue—a system for publishing both my homepage and wiki pages.

There are some existing options:

What I wanted is a unified content management (markdown files + obsidian) and a tool that I can simply point at my existing vault, tell it which pages are public, and get a website. No restructuring. No copying files into a separate project. And the vault acting as the site source. Update a markdown file, I rebuild, and it’s live.

That’s foliate.

Key ideas#

Installation#

uv tool install foliate

Or run it directly without installing:

uvx foliate build

Quick start#

From inside your vault:

uvx foliate init    # creates .foliate/config.toml
uvx foliate watch   # watch changes, rebuild, and serve locally
uvx foliate build   # generates site to .foliate/build/

That’s it. Edit .foliate/config.toml to set your site name, URL, and navigation. Mark pages as public by adding frontmatter:

---
public: true
published: true
---

Then rebuild.

Visibility system#

Foliate’s visibility model is intentionally simple:

Frontmatter Result
(nothing) Private. Not built.
public: true Built. Accessible via direct URL. Hidden from listings.
public: true, published: true Built. Visible in listings, search, and feed.

This lets you share work-in-progress pages by link without cluttering your public index.

Directory conventions#

Special directories use an underscore prefix:

Directory Behavior
_homepage/ Content deployed to site root (/) instead of /wiki/
_private/ Always ignored, regardless of frontmatter

Everything else — markdown files, nested folders, whatever structure you already have — maps to /wiki/Your/Path/.

URLs can be slugified (slugify_urls = true in [build], the default for new sites): spaces become hyphens, so you get /wiki/My-Page/ instead of /wiki/My%20Page/. Legacy space-based URLs keep working via lightweight redirect stubs with canonical tags, and the build errors clearly if two pages would collide on the same slug.

Configuration#

.foliate/config.toml controls everything. Key sections:

[site]
name = "My Wiki"
url = "https://example.com"
author = "Your Name"

[build]
wiki_prefix = "wiki"          # URL prefix for wiki content
home_redirect = "about"       # Where / redirects to
ignored_folders = ["_private"] # Folders to skip

[nav]
items = [
    { url = "/about/", label = "About" },
    { url = "/wiki/Home/", label = "Wiki" },
]

[feed]
enabled = true
items = 20
window = 30   # days to include

Atom feed#

Foliate generates an Atom feed at /feed.xml for published wiki content. It distinguishes between new pages (individual entries) and recently updated pages (a single digest entry). Configure the time window and entry count in [feed].

The default theme ships a client-side search overlay backed by a generated search.json index. Press / or Cmd/Ctrl-K on any page to open it; it filters published pages by title, tags, and a content preview. No server, no third-party service.

Quarto support#

Foliate can preprocess .qmd (Quarto markdown) files to .md before building—enable with quarto_enabled = true under [advanced]. The Quarto CLI is installed separately, and Python documents need a Jupyter kernel with jupyter-cache.

The caching is designed so writing doesn’t trigger computation: each QMD page keeps a stable execution cache, so editing prose regenerates the Markdown while Quarto reuses the Jupyter results as long as the executable cells are unchanged. foliate build --force refreshes them. Generated figures are only replaced when their contents change, keeping modification times stable.

Generated figures land in assets/quarto/ by default and deploy with the rest of the site. If you don’t want generated figures in git, add a .foliate/assets.toml with a [publisher] config (e.g., an aws s3 sync command): Foliate then keeps figures in .foliate/cache/quarto/assets/, local builds stay self-contained, and foliate deploy uploads only the figures referenced by public pages, rewriting their URLs in a separate deployment copy.

Deployment#

Built-in deployment to GitHub Pages:

foliate deploy             # build, rsync to target repo, commit, push
foliate deploy --dry-run   # preview without executing
foliate deploy --no-build  # deploy existing .foliate/build/ as-is

As of v0.9.0, deploy builds the site first by default.

Configure in [deploy]:

[deploy]
method = "github-pages"
target = "../my-site.github.io"
exclude = ["CNAME", ".gitignore"]

Watch mode#

For local development:

foliate watch

This builds, starts a local server, and auto-rebuilds on file changes.

CLI reference#

foliate init              # Create .foliate/config.toml
foliate build             # Build site
foliate build --force     # Force full rebuild
foliate build --serve     # Build + local server
foliate watch             # Build + serve + auto-rebuild
foliate status            # Preview build changes without building
foliate deploy            # Build + deploy to configured target
foliate deploy --dry-run  # Preview deployment
foliate deploy --no-build # Skip the pre-deploy build
foliate clean             # Remove build/ and cache/
foliate doctor            # Check configuration and template availability

Receive my updates

YY's Random Walks — Science, academia, and occasional rabbit holes.

YY's Bike Shed — Sustainable mobility, urbanism, and the details that matter.

×