The static site

~4 min read

The static site

What the build produces.

Output structure

_site/
├── index.html                    # your index.md, or the auto-generated note listing
├── all.html                      # full note listing (only when you have a root index.md)
├── projects_lettuce.html         # a note at projects/lettuce.md
├── reading_2026_05_note.html     # a note at reading/2026/05/note.md
├── tags.html                     # overview of every tag
├── tag-project.html              # a tag page (one per tag)
├── tag-project_lettuce.html      # nested tag project/lettuce
├── graph.html                    # link-graph view
├── graph.json                    # nodes + edges for the graph
├── sitemap.xml                   # only emitted when --base-url is given
├── search.json                   # client-side search data
├── 404.html
└── assets/
    ├── reader.css
    ├── lettuce-search.js
    ├── lettuce-graph.js              # graph view
    ├── lettuce-chart.js              # ```chart blocks
    ├── hljs.js, hljs-light.css, hljs-dark.css
    ├── katex.js, autorender.js
    ├── mermaid.js
    └── favicon.svg, favicon-32.png, apple-touch-icon.png

Every published note becomes one flat .html file: the relative path with / replaced by _ (so projects/lettuce.mdprojects_lettuce.html). A root-level index.md is treated as the curated home (index.html); when present, the auto-generated full listing moves to all.html. Without a root index.md, that listing is index.html.

The default output directory is <vault>/_site. Change it with lettuce publish --out <dir>.

Theming

There is one built-in theme: assets/reader.css, with a light/dark color scheme that follows the reader’s system preference (<meta name="color-scheme" content="light dark">). There are no theme variants or theme-selection flags — the look is fixed.

Site configuration

There is no site-config file. Everything the build needs is passed on the command line:

lettuce publish [vault] \
  --out _site \
  --base-url https://notes.example.com \
  --contact you@example.com \
  --all

See CLI cookbook/03 lettuce publish for the full flag list.

Tag pages

Every tag used in published notes gets a generated page at tag-<tag>.html, plus an overview at tags.html. Tag pages are nested-aware: a parent tag’s page also lists notes from its descendant tags. There is no tag-configuration file — descriptions, colors, and pinning are not configurable.

Nested tags map to _-joined filenames: project/lettucetag-project_lettuce.html.

Lettuce builds a client-side search index at _site/search.json and bundles a small search widget at _site/assets/lettuce-search.js. The search box lives in the site header. No server required.

The full content of every published note is indexed; non-published notes are never present in the index. There is no setting to disable search.

OG and meta

Each note page gets:

<meta property="og:type" content="article">
<meta property="og:site_name" content="…">
<meta property="og:title" content="…">
<meta name="twitter:title" content="…">
<meta name="description" content="…">          <!-- the next three only when a description exists -->
<meta property="og:description" content="…">
<meta name="twitter:description" content="…">
<meta property="og:url" content="…">           <!-- only when --base-url is set -->
<meta property="og:image" content="…/assets/apple-touch-icon.png">
<meta name="twitter:card" content="summary">

The title comes from the note. The description is the note’s description/summary frontmatter, falling back to the lead text. og:image is always the site’s apple-touch-icon.png — there is no per-note image key.

A wikilink to a published note becomes a regular <a> to its flat .html file. A wikilink to a non-published note is rendered as plain text — no broken external links from your site.

Performance

The renderer is fast — roughly 6000 notes in ~18 seconds on Apple silicon. Per-note rendering runs across cores; the index, search, graph, and tag pages are assembled once at the end. Each lettuce publish is a full build.