Styx

Nix-based static site generator. Sites are defined entirely in Nix expressions; content is written in Markdown, AsciiDoc, or native Nix and rendered via customizable themes.

Key Features

  • All templates, logic, and data use the same Nix expression language
  • Efficient incremental builds via Nix’s caching (only modified content is rebuilt)
  • Minimal dependencies — only Nix required
  • Type-checked configuration via NixOS module system
  • Automatic SASS/SCSS compilation
  • Embedded Nix expressions inside markup files ({{ expr }})
  • Multipage / paginated content via mkSplit
  • Taxonomy system (mkTaxonomyData / mkTaxonomyPages)
  • Built-in link checker (styx linkcheck)

Limitations

  • Markup conversion can be slow (mitigated by caching on rebuilds)
  • Requires learning the Nix expression language

Installation

# Temporary shell
nix shell github:styx-static/styx

Quick Start

styx new site my-site
cd my-site
styx preview          # serve at http://127.0.0.1:8080
styx doc              # open full HTML documentation in browser

Preview a bundled theme without creating a site:

styx preview-theme showcase

CLI Reference

Generic Flags

FlagDescription
--helpDisplay help
--versionDisplay version
--in DIRRun command in specified directory
--file FILEUse a custom file instead of site.nix
--draftsInclude draft content in build
--show-traceShow debug trace on failure
--arg NAME VALUEPass argument to main function
--argstr NAME VALUEPass string argument to main function
-I PATHAdd path to Nix expression search path

Commands

CommandDescription
styx new site NAMECreate a new site in current directory
styx new site NAME --in DIRCreate site in DIR/NAME
styx new theme NAME --in DIRCreate a new theme skeleton
styx buildBuild site to public/ directory
styx build --out DIRBuild to custom output directory
styx store-pathReturn the Nix store path of the built site
styx previewStart local server at 127.0.0.1:8080
styx preview --port 9090Start server on custom port
styx preview-theme NAMEPreview a bundled theme
styx liveAuto-rebuilding live preview (quit with q)
styx serveBuild and serve site on port 8080
styx serve --detachServe in background
styx linkcheckValidate all links in the built site
styx docOpen HTML documentation in browser
styx site-docGenerate and display site-specific docs
styx gen-dataGenerate sample data in ./data
styx theme-path NAMEPrint the store path of a bundled theme
styx deploy --init-gh-pagesInitialize gh-pages branch for GitHub Pages
styx deploy --gh-pagesBuild and deploy to GitHub Pages

Project Structure

A minimal site only needs site.nix. The styx new command scaffolds:

my-site/
├── conf.nix       # site configuration
├── default.nix    # allows building with plain `nix build`
├── site.nix       # core site logic
├── data/          # content (Markdown, AsciiDoc, Nix files)
└── themes/        # custom/local themes

site.nix Structure

A site.nix is conventionally divided into sections:

# 1. Init — load styx library
# 2. Themes — declare themes and load their assets/conf
# 3. Data — load content files with loadFile / loadDir
# 4. Pages — declare pages (path, template, layout)
# 5. Site — call mkSite with the pages list

Every page must declare three attributes:

AttributeDescription
pathOutput file path, must start with / (e.g. "/index.html")
templateFunction page -> page that processes the page data
layoutFunction page -> string that wraps the template output

Generation evaluates page.layout (page.template page) for each page.

Configuration (conf.nix)

Configuration is merged from three sources (highest priority last):

  1. Theme’s own conf.nix
  2. Site root conf.nix
  3. extraConf passed via CLI

conf.nix can be a plain attribute set or a function returning one (receives { lib }).

The only required field is siteUrl — must not end with /:

{
  siteUrl = "https://example.com";
 
  theme.site.title = "My Site";   # override theme config
}

Content / Data

Loading Content

data = {
  posts = loadDir { dir = ./data/posts; };   # list of attr sets
  about = loadFile { file = ./data/pages/about.md; };
};

loadFile / loadDir automatically:

  • Parse YAML front matter (between --- delimiters)
  • Extract introductions
  • Evaluate embedded {{ nix }} expressions

Supported Formats

FormatUse caseProcessor
MarkdownSimple posts and pagesPandoc → content attr
AsciiDocComplex documents with rich formattingAsciidoctor
NixComplex data structures, parameterized dataNative

Drafts

Mark a file as a draft in front matter:

---
draft: true
---

Drafts are excluded unless --drafts flag is passed or renderDrafts = true in conf.

Taxonomies

taxonomyData = mkTaxonomyData { data = posts; taxonomies = [ "tags" "author" ]; };
taxonomyPages = mkTaxonomyPages { data = taxonomyData; ... };

Page Types

TypeFunctionDescription
SimpleSingle page with required attributes
Data-attached//Merge external data into a page
Split/PaginatedmkSplitDistribute a list across multiple pages with pagination metadata
MultipagesmkMultipagesHierarchical nested page sets
Page listmkPageListProduces list (no subpages) and pages (all) attributes
TaxonomymkTaxonomyPagesIndex + term pages from taxonomy data

Themes

Available Bundled Themes

ThemeDescription
agencyBusiness / corporate
generic-templatesFlexible reusable templates
ghostwriterContent-focused, readable
hydeSidebar layout
nixMinimalist
orbitModern / portfolio
showcasePortfolio / showcase

Using Themes in site.nix

themes = [ pkgs.styx-themes.hyde ];   # official theme
# or
themes = [ ./themes/my-theme ];        # local theme

Items at the beginning of the list have lower priority; later entries override earlier ones — useful for layering a customization theme on top of a base theme.

Creating a Theme

styx new theme my-theme --in ./themes

Scaffold:

my-theme/
├── conf.nix       # typed or untyped configuration interface
├── meta.nix       # metadata — must include `id` attribute
├── files/         # static assets copied to generated site
├── templates/     # template .nix files
└── lib.nix        # (optional) custom functions

Theme config is merged into conf.theme and can be overridden from the site’s conf.nix.

Deployment

GitHub Pages

styx deploy --init-gh-pages   # one-time: creates gh-pages branch
styx deploy --gh-pages        # build + commit to gh-pages branch

Amazon S3

aws s3 sync $(styx store-path) s3://<bucket-name>/