Zealous Efficient Static Toolkit
License · Quick Start · Docs
Zest is a hybrid F# + C# static site generator where templates are real code — not strings. Built on the philosophy that your templating language and your host language should be one and the same.
- Template as Code —
.zest.fsxare real F# scripts executed at build time viadotnet fsi. Full F#: list comprehensions, pattern matching, string interpolation, arbitrary computation. .zhtmlLightweight Pages — Pure HTML pages with optional Nunjucks template syntax. No FSI overhead.- HTML DSL — Compose HTML declaratively:
render [ h1 []; p [] ]. - Inline Markdown — Write Markdown directly inside a
.zest.fsxpage with themdhelper and mix it with the HTML DSL:md """# Title\n**bold**""". - Markdown — Standard
.mdfiles with frontmatter support. - ZCSS — A CSS superset with nesting, F#-style
letbindings, math expressions, color functions, and mixins — compiled to standard CSS. - 11ty-Compatible Templates — Full Nunjucks (.njk), Liquid (.liquid), Handlebars (.hbs), Mustache (.mustache), HAML (.haml), Pug (.pug), and WebC (.webc) support — all with auto-conversion to Nunjucks engine for filters, macros, template inheritance, and Zest API integration.
_init.fsx— Optional initialization script (runs before build) to inject dynamic data, load JSON/TOML, read env vars.- TOML Config — Zero-config defaults; customize via
_config.tomland_data/*.toml. No YAML. - Live Reload —
zest servewatches for changes and auto-rebuilds. - Batch Evaluation — Multiple F# page scripts evaluated in a single FSI process for fast builds.
- Incremental Builds — File change detection skips unchanged pages and assets.
- Cross-Platform — Builds for Windows x64, Linux x64/ARM64, macOS ARM64.
# Scaffold a new project
zest init my-site
# Develop with live reload
cd my-site && zest serve --port 8080
# Build for production
zest build
# Preview the built site
zest preview// @title Hello World
// @layout default
// @description My first Zest page
let pageTitle = "Hello from F#"
let items = ["F#"; "Zest"; "SSG"]
render [
h1 [ text pageTitle ]
p [ text "This page is generated by real F# code at build time." ]
ul [ for i in items -> li [ text i ] ]
]The md helper renders a Markdown string to an HTML string, so you can blend
prose with the F# HTML DSL in the same page — md returns a plain string,
just like every other DSL builder:
// @title About
// @layout default
open Zest.Dsl
render [
divC "about" [
md """
# About
This page is a **native template** written in `.zest.fsx` (real F#), where
Markdown and the HTML DSL live side by side.
Learn more at the [Zest repository](https://github.com/zest-ssg/zest).
"""
]
]// F#-style let bindings with math expressions
let primary = #3b82f6
let space1 = 0.25r
let space4 = space1 * 4 // 1rem
let primary-light = primary |> lighten(45%)
// Two-letter property shorthands
.tag
color: $primary
background-color: $primary-light
padding-block: $space4
border-radius: 9999px
Compiles to:
.tag {
color: #3b82f6;
background-color: #adf4ff;
padding-block: 1rem;
border-radius: 9999px;
}// _init.fsx — runs before every build
addGlobal "api_url" "https://api.example.com"
let team = loadJson "data/team.json"
addGlobal "team" team
let env = loadEnv "ZEST_ENV"
if env = "production" then
addGlobal "analytics_id" "UA-XXXXX-Y"my-site/
├── _config.toml # Site configuration (TOML)
├── _init.zest.fsx # Optional init script (runs before build)
├── _data/
│ └── site.toml # Global data (accessible from scripts/templates)
├── content/
│ ├── index.zest.fsx # Home page (F# script template)
│ ├── about.md # About page (Markdown)
│ └── posts/
│ ├── hello-world.zest.fsx
│ └── contact.zhtml # Pure HTML (no FSI overhead)
├── _layouts/
│ ├── default.html # Layouts (Nunjucks or native replace)
│ └── post.html
├── assets/
│ └── css/
│ └── style.zcss # ZCSS → auto-compiled to style.css
└── _site/ # Build output (auto-generated)
| Project | Language | Responsibility |
|---|---|---|
| Zest.App | C# | CLI entry point, command routing |
| Zest.Engine | F# | Core engine: builds, HTML DSL, ScriptRunner, Markdown, ZCSS compiler, Nunjucks template engine, 11ty-compatible language layer |
| Zest.Dsl | F# | Precompiled DSL helpers for FSI script evaluation |
| Zest.Infra | C# | Configuration loading, file watching, dev server |
git clone https://github.com/zest-ssg/zest
cd zest
dotnet build Zest.sln
# Publish for your platform
dotnet publish src/Zest.App/Zest.App.csproj -c Release -r win-x64 --self-contained false
# Linux: -r linux-x64
# macOS: -r osx-arm64| Extension | Purpose | Processing |
|---|---|---|
.zest.fsx |
F# script templates (F# + Markdown + HTML DSL) | Compiled via dotnet fsi |
.njk |
Nunjucks templates (filters, macros, inheritance, Zest API) | Rendered via NunjucksEngine |
.liquid |
Liquid templates (Jinja2 family, auto-converted) | Converted → NunjucksEngine |
.hbs |
Handlebars templates (auto-converted to Nunjucks) | HandlebarsMustacheConverter → NunjucksEngine |
.mustache |
Mustache templates (auto-converted to Nunjucks) | HandlebarsMustacheConverter → NunjucksEngine |
.webc |
WebC components (SSR preprocessed) | WebC preprocessor → NunjucksEngine |
.haml |
HAML templates (auto-converted to HTML → Nunjucks) | HamlConverter → NunjucksEngine |
.pug |
Pug templates (auto-converted to HTML → Nunjucks) | PugConverter → NunjucksEngine |
.zcss |
ZCSS stylesheets (CSS superset) | Compiled to .css |
.md |
Standard Markdown | Rendered to HTML |
.toml |
Configuration and data (no YAML) | Parsed at build time |
| Command | Description |
|---|---|
zest build |
Build the site to _site/ |
zest serve |
Start dev server with live reload |
zest preview |
Preview the built site |
zest init <name> |
Scaffold a new project |
zest clean |
Clean build output |
| Feature | Syntax |
|---|---|
| Variables (SCSS) | $name: value; |
| Variables (F#) | let name = value |
| Math | let x = 0.25r * 4 |
| Color functions | lighten(#hex, %), darken(#hex, %), mix(a, b, %) |
| Pipe operator | value |> fn(args) → fn(value, args) |
| Unit shorthands | r→rem, p→% |
| Property shorthands | py→padding-block, mx→margin-inline, bgc→background-color |
| Nesting | Indent or brace mode |
| Mixins | @mixin, @include |
| Loops | @each, @for |
| Conditionals | @if, @else |
| Built-in modules | @use "zest:utilities", @use "zest:palette", etc. |
| Engine | Config Value | Features |
|---|---|---|
| Nunjucks (default) | template_engine = "nunjucks" |
Filters, expressions, {% if %}, {% for %}, macros, template inheritance, Zest API filters (pages_by_tag, recent, by_collection, search, where) — also handles .liquid, .hbs, .mustache, .webc, .haml, .pug via auto-conversion |
| Native Replace | template_engine = "replace" |
Simple {{ variable }} substitution |
// Elements
h1 [ text "Title" ]
p [ text "Paragraph" ]
a [ href "https://example.com"; text "Link" ]
// Attributes
div [ class' "container"; id "main" ] [ ... ]
// CSS class shortcuts
divC "card" [ p [ text "Content" ] ] // <div class="card">
spanC "badge" [ text "New" ] // <span class="badge">
// List comprehensions
ul [ for item in items -> li [ text item ] ]
// Conditionals
if condition then
p [ text "Yes" ]
else
p [ text "No" ]| Function | Purpose |
|---|---|
addGlobal key value |
Inject key-value into global data |
loadJson path |
Parse JSON file |
loadToml path |
Parse TOML file |
loadEnv key |
Read environment variable |
console_log msg |
Debug output to stderr |
exec cmd args |
Run shell command |
Zest is not a general-purpose static site generator. It is a specific answer to specific constraints.
- F# as the Template — The template is the program.
.zest.fsxfiles are real F# code, not strings. - ZCSS as the Layout Engine — Not a CSS pre-processor, but a layout engine that emits CSS.
- TOML as the Contract — No YAML. Ever.
- JavaScript as Order — No Node.js, no npm, no bundlers. JavaScript exists only for client-side interactivity.
- The Zealous Few — Built for those who love F#, hate YAML, and prefer simple tools.
Zest would not have been possible without the help of my capable AI assistants, who supported me through design, debugging, and documentation:
- Claude — architecture and design review
- GLM — research and experimentation
- DeepSeek — debugging and performance tuning
- Hunyuan — implementation and documentation support
Thank you all for helping bring this project to life.
Apache 2.0 — see LICENSE.