Content files
Markdown files with YAML frontmatter — the source of truth for every page.
Every page on a juicer site comes from a markdown file under content/. There are two flavors:
- Section index — a file named
_index.md(configurable viafolderContent). Renders toindex.htmlat the section directory. Carries the section’s title, summary, and any list-page customizations. - Single page — every other markdown file (
foo.md). Renders to its ownfoo/index.htmlfor clean URLs.
content/
├── _index.md → /index.html
├── about.md → /about/index.html
└── docs/
├── _index.md → /docs/index.html
├── installation.md → /docs/installation/index.html
└── api/
├── _index.md → /docs/api/index.html
└── spec.md → /docs/api/spec/index.html
Frontmatter
Every content file may begin with a YAML frontmatter block, delimited by ---:
---
title: My page
summary: One-line description shown in lists and meta tags.
weight: 30
draft: false
---
# Welcome
The body is plain markdown.
Recognized frontmatter keys:
| Key | Type | What it does |
|---|---|---|
title | string | Page title; used by templates and search index |
summary | string | Explicit summary; overrides auto-derived |
weight | int | Sort key inside the section (lower = first) |
draft | bool | Skip the page unless --drafts is passed |
| anything | any | Available to templates as .page.<key> |
The frontmatter format is YAML. JSON and TOML frontmatter are not supported — partly because YAML covers the use case fluently, partly because supporting three formats triples the surface area to keep correct.
Pretty URLs
Both flavors of content render to index.html so that URLs don’t carry file extensions. about.md becomes /about/, not /about.html. The _index.md for a section becomes /docs/, not /docs.html.
The htmlDir quirk
By default (the standard baseline config) juicer writes nested sections to dst/html/<section>/... rather than dst/<section>/.... That html/ segment is filesystem-only — every URL juicer emits has it stripped. The convention exists so that:
- The site root
index.htmllives at the top ofdst/, alongsidestatic/files (favicon.ico,robots.txt, etc.). - Nested content stays under a single subtree, so a webserver root pointing at
dst/doesn’t conflate static assets with rendered pages.
If this surprises you, set htmlDir = "" in your site.toml to disable. Most users don’t need to touch it.
Page bundles
Drop non-markdown files (images, attachments, anything that isn’t .md/.toml/.yaml/.html) next to a page’s markdown and they ride along as bundle assets:
content/iceland-2024/
_index.md
hero.jpg
skogafoss.jpg
hero.jpg is copied to the section’s output directory and served from /iceland-2024/hero.jpg. Templates iterate .page.assets to render a gallery or attachments list, and imageVariants 'hero.jpg' (no leading slash) resolves bundle-relative — move the bundle, the markup follows.
Full reference (record shape, resolution rules, when NOT to use a bundle) in Template data → Page bundles.
Drafts
A page with draft: true is skipped entirely during a normal build — invisible to the TOC, sitemap, search index, and section listings. To preview drafts locally, pass --drafts (or -D):
sbt 'juicerJVM/run serve -s docs -D'
Scheduling future posts
A page whose parsed date: frontmatter is in the future is skipped during a normal build, the same way draft: true is — invisible to every downstream consumer. The intended workflow is:
Set the publication date in frontmatter
---
title: Big announcement
date: 2024-12-25T09:00:00Z
---
Push the post to your repo whenever it’s done
The post is invisible to a normal juicer build until the system clock catches up.
Re-build (or re-deploy) on or after the publication date
The post starts appearing in section listings, taxonomy archives, feeds, and the sitemap automatically. Most people set up a daily build cron or use a CI scheduler.
To preview future-dated posts locally, pass --future (or -F):
sbt 'juicerJVM/run serve -s docs -F'
--future and --drafts are independent flags. A post with draft: true and a future date requires both flags to render.
The future-skip rule only applies to pages with explicit date: frontmatter. Pages relying on the filesystem-mtime fallback are never future-skipped — mtime can’t be in the future under any normal workflow, but the safer rule is “only authored future-dating counts”.
Summaries
Every page exposes a .page.summary. Three sources are tried, in order:
Explicit frontmatter
If summary: ... is set in frontmatter, it’s used verbatim. Stop.
<!--more--> marker
The body up to (but not including) <!--more--> is rendered as HTML and used as the summary. Useful when the natural summary is the first paragraph or two but you don’t want to repeat yourself.
First paragraph (fallback)
The first paragraph’s plain text, capped at 30 words and ellipsised. Hugo defaults to 70 words; juicer trims tighter for compact list pages.