1. Introduction

Styx is a functional static site generator written in the Nix expression language.

Styx is aimed to be flexible and easy to customize. It is based on the Nix package manager, so it gets many of its advantages: caching system and build determinism to name a few.

Styx was inspired by the NixOS weekly project and the Hugo static site generator.

For users familiar with Nix, Styx is best described as a custom nix builder to generate static websites.

1.2. Styx Overview

Pros:

  • Uniformity: The same language is used for templates and logic (and can be used for data too).

  • Caching: Styx benefits of the Nix caching system, so only needed pages are rebuild.

  • Light weight: Styx has very few dependencies.

  • Flexibility: Styx is very flexible which makes it easy to implement new features.

  • Integration with the Nix ecosystem: Styx sites can be deployed with NixOps, and continuous integration can be done with Hydra.

  • Documentation: Styx has extensive documentation and per site documentation can be generated.

Cons:

  • Performance: Some parts of Styx like markup file conversion can be quite slow, this is partly counter-balanced by the caching system, but on a fresh site generation Styx can be magnitudes slower than other static site generators.

  • Semantics: Styx uses the Nix expression language for its logic and templates. The Nix expression language is quite different of usual languages and can need some time to get familiar with.

  • Nix: Styx has only one dependency, the Nix package manager. To use Styx you must install Nix, and depending your platform, that can be challenging. But installing Nix might totally change your views on package management!

2. Installation

The only requirement for installing Styx is the Nix package manager. Refer to the Nix installation instructions to install Nix.

It is possible to install styx with the following command:

$ nix-env -i styx

For testing purposes, nix-shell can be used to start a temporary environment with styx:

$ nix-shell -p styx

Newer versions of styx are available in the nixpkgs-unstable or nixos-unstable channel, but there might be some delay between a styx release and the time the channel get updated.

It is possible to directly install the latest version of styx by running the following command:

$ nix-env -i $(nix-build https://github.com/styx-static/styx/archive/latest.tar.gz)

Or to start a nix-shell with the latest styx stable version:

$ nix-shell -p $(nix-build https://github.com/styx-static/styx/archive/latest.tar.gz)

3. Quick Start

3.1. Preview a styx site

The styx showcase theme example site can be previewed by the following command:

$ styx preview-theme showcase

This command downloads the showcase theme to the nix store, builds the site (also in the nix store) and launches the preview from there.

The showcase example site will be accessible at http://127.0.0.1:8080. Check the posts as they provide some information about how styx works.


3.2. Create a new site

To create a new site, the following set of commands can be used:

$ styx new site my-site (1)
$ cd my-site (2)
1 Initialize a new styx site in the my-site directory.
2 Enter the my-site directory.

A readme.md file will be available in the my-site directory giving basic instructions. Also the styx doc command will launch the documentation in a browser.

It is recommended to read the site.nix section of this documentation to get familiar with how site.nix is structured and works.

Each theme of the styx-themes set provides an example site with a site.nix that can be checked in the themes documentation.

4. Basics

Styx uses the Nix expression language. The Nix expression language is a lazily evaluated functional language with uncommon semantics.
It is recommended to read the Nix expression language chapter of the Nix manual to get more familiar with it.

4.1. Hello world!

Let’s look at a very basic example of a styx site site.nix file.

Hello world!
{ styx, ... }@args: (1)

rec { (2)

  lib = import styx.lib styx; (3)

  index = { (4)
    layout   = template: "<html><body>${template}</body></html>"; (5)
    template = page: '' (6)
      <h1>Styx example page</h1>
      ${page.content}
    '';
    content = "<p>Hello world!</p>"; (7)
    path    = "/index.html"; (8)
  };

  site = lib.mkSite { pageList = [ index ]; }; (9)

}
1 site.nix is a function written in the nix language. Nix functions have the { arg1 ? default, arg2, …​, argN, …​ }: body pattern.
The arguments of the function are the dependencies needed to build the site.
@args refers to the whole argument set.
2 { starts a set. rec makes the set recursive, meaning that attributes can refer to each other.
3 This imports the styx library in a lib attribute.
4 This declares an index attribute as an attribute set. An attribute set is a basic key-value structure. index will be the only page generated.
5 To generate a page, styx requires a few attributes to be set, namely layout, template and path. This line declares the layout attribute that is a function that takes the template argument and returns the page source.
template: form is different from the first point function head, this function use a simple parameter (Point one was using a deconstructed attribute set parameter).
6 This declares a template attribute. template is a function that takes the page attribute set, page (in this case as a parameter) and generates a result that will be passed to the layout function.
7 This declares a content attribute. This is not mandatory, and could have been integrated in the template key. But most of styx data fetchers will add a content attribute to the page set containing the fetched content.
8 This declares a path attribute. The path attribute is used to specify the path of the page to be generated.
9 This generates the site by using the library mkSite function, its parameter is an attribute set with the argument pageList being a list of the single index page.

Everything is ready, the "Hello world!" site preview can be generated.

Generating a preview of the "Hello world!" site
$ styx preview
Even if this is a simple example, nix language semantics can be confusing.
In a nutshell, to build a site, mkSite evaluates page.layout (page.template page) and output the result in page.path for every page in pageList.
That is the reason layout, template and path are required attributes of a page set.
Nix expression language is lazily evaluated, so infinite data structures are not a problem (unless some code tries to evaluate them).

4.2. Files

In its simplest form, styx just needs a site.nix to generate a site like presented in the Hello world! example.

But the styx new command will generate a few more files for convenience.

├── conf.nix    (1)
├── default.nix (2)
├── readme.md   (3)
├── site.nix    (4)
├── data/       (5)
└── themes/     (6)
1 conf.nix is the main configuration file, see Configuration for details.
2 default.nix is a file that can be used to build a styx file directly with nix-build.
3 readme.md provides some basic information about how to start using styx.
4 site.nix is the main file for site generation, see site.nix for details.
5 data/ is an empty directory meant to hold site data.
6 themes/ is an empty directory meant to hold custom themes.
The file structure of a styx site is totally free and can be changed according to needs.
It is even possible to change the name of site.nix. In that case the --file flag of the styx command can be used to specify the file name.

4.3. site.nix

The site.nix used in the Hello world! example contains only enough code to generate a single page. A standard site.nix is usually more structured.

A complex example of a site.nix if the showcase theme example site.nix that uses almost every feature available.

A standard site.nix is divided in multiple sections, each section handling a particular topic.
Standard sections are:

4.3.1. Init

This section is the basic setup of styx, it should not be changed and used as is for most setups.

Standard Init section
/*-----------------------------------------------------------------------------
   Init

   Initialization of Styx, should not be edited
-----------------------------------------------------------------------------*/

{ styx
, extraConf ? {}
}@args:

rec {

  /* Styx library
  */
  styxLib = import styx.lib styx; (1)
1 Load the styx library, library functions are documented in library documentation.

4.3.2. Themes

The theme section is responsible for loading themes assets (configuration, library, static files, and templates).

Themes are detailed in the Themes section.

Standard themes section
/*-----------------------------------------------------------------------------
   Theme setup

-----------------------------------------------------------------------------*/

  /* Importing styx themes from styx
  */
  styx-themes = import styx.themes; (1)

  /* list the themes to load, paths or packages can be used
     items at the end of the list have higher priority
  */
  themes = [ (2)
    styx-themes.generic-templates
  ];

  /* Load the theme data
  */
  themeData = styxLib.themes.load {
    inherit styxLib themes;
    extraEnv = { inherit data pages; }; (3)
    extraConf = [ ./conf.nix extraConf ]; (4)
  };

  /* Bring the theme data into scope
  */
  inherit (themeData) conf lib files templates env; (5)
1 Importing the styx-themes.
2 themes is a list so it is possible to set multiple themes at the same time to combine them. Themes at the beginning of the list have a lower priority.
Themes can be paths like ./themes/my-site or packages from the styx-themes set.
3 Extra variables to add to the template environment.
4 Extra configuration sets to merge with the themes configurations, can be files or paths, head of the list have lower priority.
5 Bringing the themeData attributes in the scope.

4.3.3. Data

The data section is responsible for loading the data used in the site.

The Data section explains in detail how to manage data.

Standard data section
/*-----------------------------------------------------------------------------
   Data

   This section declares the data used by the site
-----------------------------------------------------------------------------*/

  data = {
    about = lib.loadFile { file = ./pages/about.md; inherit env; }; (1)
  };
1 Example of loading a Markdown file with the loadFile function.

4.3.4. Pages

The pages section is used to declare the pages that will be generated by mkSite.
Even if mkSite expects a page list, it is usually declared as an attribute set for convenience.

There are multiple functions available to generate different type of pages, but a page is ultimately an attribute set with at least the layout, template and path attribute defined.

The Pages section explains in detail how to create pages.

Standard pages section
/*-----------------------------------------------------------------------------
   Pages

   This section declares the pages that will be generated
-----------------------------------------------------------------------------*/

  pages = {

    about = {
      path     = "/about.html";
      template = templates.page.full;
      layout   = templates.layout;
    } // data.about; (1)

  };
1 // is the operator to merge attribute sets, this merge the data.about data attribute set in the pages.about page attribute set.
path must start with a /.

4.3.5. Site

This is the final part and shortest section of site.nix. This section consists of a call to mkSite.

Standard mkSite section
/*-----------------------------------------------------------------------------
   Site

-----------------------------------------------------------------------------*/

  /* Converting the pages attribute set to a list
  */
  pageList = lib.pagesToList { inherit pages; }; (1)

  site = lib.mkSite { inherit files pageList; }
}
1 mkSite requires pages as a list, so pagesToList converts the pages attribute set to a list.
files is generated in the theme section using enabled themes.
inherit is a shorthand for writing sets, { inherit a; } is equivalent to { a = a; }.

4.3.6. site.nix in a nutshell

site.nix is a function:

  • taking at least nixpkgs lib, styx, runCommand and writetext attributes.

  • returning an attribute set with a site attribute using the mkSite function.

mkSite is a function:

  • taking at least a list of pages to generate as the pageList argument.

  • evaluating each page set by evaluating page.layout (page.template page) and outputting the result in page.path.

  • returning a generated static site directory.

mkSite is a wrapper for nixpkgs runCommand function.

5. Configuration

In a standard site.nix, the configuration is generated by merging multiple configuration sources (lower to higher priority):

  • Theme’s default configuration (interface) (every used theme’s conf.nix).

  • conf.nix in the site root directory, the main configuration of a styx site.

  • site.nix function head extraConf argument, used by the styx cli to override configuration keys according to passed options, mainly siteUrl and renderDrafts.

Configuration loading is done in site.nix theme section and can be adapted to fit needs.

5.1. conf.nix

conf.nix is the central configuration file of a styx site, its default location is at the site root.

This file consist in an attribute set, or a function returning an attribute set, that defines configuration options.
In case of a conf.nix is a function, it will be called with { lib = lib; } agument.

Themes are configured via the theme attribute, every theme defines a configuration interface that can be used in conf.nix.

siteUrl is the only required field, and must not end with a slash.
It can be a domain like http://www.domain.org or a domain and a path like http://www.domain.org/styx-site.

Standard conf.nix
{ lib }:
{
  # URL of the site, must be set to the url of the domain the site will be deployed
  siteUrl = "http://yourdomain.com";

  # Theme specific settings
  # it is possible to override any of the theme configuration settings in the 'theme' set
  theme = {
    # Changing the theme site.title setting
    site.title = "Styx Site";
  };
}
conf.siteUrl must not end with a /.

6. Themes

Themes are a central concept in styx and are used to manage a site assets, like static files and templates. They can also provide a configuration interface and a function library.

6.1. Getting themes

Styx themes that are part of the styx-themes package set are documented in the styx-themes documentation.

6.2. Creating a new theme

A new theme file structure can be created by running the styx new theme command.

Creating a new theme
$ styx new theme my-theme --in ./themes

This command will generate the following files in ./themes/my-theme:

├── conf.nix   (1)
├── meta.nix   (2)
├── files/     (3)
└── templates/ (4)
1 Theme configuration interface, see Configuration interface for details.
2 Theme meta data, see Metadata for details.
3 Directory to store theme static files, see Files for details.
4 Directory to store theme templates, see Templates for details.

See Structure for details.

Site and themes both have conf.nix files, their purpose is different and should not be confused.
The theme’s conf.nix defines the configuration interface, and the site’s conf.nix settings use this interface to customize the theme.

6.3. Using themes

Declaring used themes is done in the theme section of site.nix. Paths or packages can be used.

Using a local my-site theme and the generic-templates theme
  styx-themes = import styx.themes;

  /* list the themes to load, paths or packages can be used
     items at the end of the list have higher priority
  */
  themes = [
    styx-themes.generic-templates
    ./themes/my-theme
  ];
Items at the beginning of the themes list have lower priority.

6.4. Structure

Themes are usually stored in a themes directory, or used from the styx-themes package set.

Every theme is stored in its own directory, and themes are expected to follow a certain structure.

Structure of a Styx theme
themes
└── NAME  (1)
    ├── conf.nix    (2)
    ├── meta.nix    (3)
    ├── lib.nix     (4)
    ├── files/      (5)
    └── templates/  (6)
1 Theme directory.
2 conf.nix defines the theme configuration interface options (optional).
3 meta.nix defines the theme meta information, this file is required and must define an id attribute.
4 lib.nix defines the theme extra library as a set (optional).
5 files is a directory holding static files for the themes. All the files in this directory will be copied in the generated site (optional).
6 templates is a directory storing all the template files (optional).

6.5. Configuration interface

Themes can provide a configuration interface by having a conf.nix file at the theme root directory.

In its simplest form, conf.nix should be an attribute set defining theme options with default values.

Example of a theme conf.nix
{
  site = {
    title = "The Agency";
    author = "Your name";
    description = "Your description";
  };
}

This configuration is merged in the conf variable theme key after theme loading, and can be used from the site configuration (site conf.nix).

Usage of a theme configuration option in a site conf.nix
{
  theme.site.title = "My Agency";
}

6.5.1. Typing

conf.nix can leverage NixOS module system like typing, and declare options with the mkOption function.

See NixOS manual option declaration chapter for mkOption usage details.

This has two benefits:

  • Site configuration, site root conf.nix, will be type checked.

  • Documentation will be automatically generated for the configuration interface.

On the other hand, typing a theme configuration interface is verbose and can be an overkill for a private theme.
Typing is not required, but should be done for themes that are part of the styx-themes theme set or meant to be shared.

types.submodule type is not supported.
Example of a theme conf.nix with typing
{ lib }:
with lib;
{
  site = {
    title = mkOption {
      default = "The Agency";
      type = types.str;
      description = "Title of the site.";
    };

    author = mkOption {
      default = "Your name";
      type = types.str;
      description = "Content of the author `meta` tag.";
    };

    description = mkOption {
      default = "Your description";
      type = types.str;
      description = "Content of the description `meta` tag.";
    };
  };
}

Options can then be used in the site conf.nix in the same manner than non-typed ones.

Wrong usage of a theme configuration option in a site conf.nix
{
  theme.site.title = 2;
}
Trying to build a site with type errors
$ styx preview
error: The configuration option `theme.site.title' is not a string.
(use ‘--show-trace’ to show detailed location information)
---
Error: Site could not been built, fix the errors and run the command again.
The '--show-trace' flag can be used to show debug information.

6.6. Metadata

Theme metadata is declared in the meta.nix file as an attribute set. Themes must define a meta.nix with an id attribute so the theme configuration is correctly processed.

Other attributes of the meta set are totally optional and can be set at will to provide information about the theme (e.g. license, description, author, homepage, …​).

meta attributes used for the generated documentation are:

  • name: Theme name, can contain any character.

  • license: A license from lib.licenses.

  • demoPage: URL of the theme example site live demo.

  • homepage: URL of the theme.

  • screenshot: Path to a screenshot of the theme example site.

  • description: A single line theme description, AsciiDoc markup can be used.

  • longDescription: Free length site description, AsciiDoc markup can be used.

  • documentation: Theme documentation, AsciiDoc markup should be used.

Example of a simple theme meta.nix
{
  id = "showcase";
}
Example of a theme meta.nix with multiple attributes
{ lib }:
{
  id          = "showcase";
  name        = "Showcase";
  license     = lib.licenses.mit;
  demoPage    = https://styx-static.github.io/styx-theme-showcase;
  homepage    = https://github.com/styx-static/styx-theme-showcase;
  screenshot  = ./screen.png;
  description = "A theme to show Styx main functionalities.";
}
Themes must define a meta.nix with an id attribute.
meta.nix can be an attribute set or a function, if it is a function it will be called with an attribute set argument containing lib.

6.7. Files

The files directory holds the static files provided by the theme. Every file in in this directory will be copied in the generated site.

If multiple themes are enabled, every theme file directory contents will be copied to the generated site.

6.7.1. Special files

Styx automatically converts SASS, SCSS and LESS files to CSS during site generation.

6.8. Library

Themes can provide a function library that can be used in site.nix or in templates.

To provide a library, a theme must have a lib.nix file containing an attribute set of functions.

To be sure a theme library functions will not override default functions it is best practice to put the functions in a dedicated namespace, theme.ID where ID is the theme ID as a natural choice.

Example of a theme lib.nix
{ lib }:
{
  theme.my-theme = {
    foo = x: "foo called with ${builtins.toString x}";
  };
}
lib.nix can be an attribute set or a function, if it is a function it will be called with an attribute set argument containing lib.

6.9. Templates

Every template in the templates directory will be accessible by its file basename in the templates attribute set. Directories are converted to nested sets.

Example of a template directory structure
├── archive.nix
└── post
    ├── full.nix
    └── list.nix
Generated attribute set
templates = {
  archive = <LAMBDA>;
  posts = {
    full = <LAMBDA>;
    list = <LAMBDA>;
  };
};
<LAMBDA> means a non fully evaluated function.
The nix language is functional, and it allows to partially apply functions, and to pass function as argument to other functions.

Styx templates are functions that return text or page attribute sets when fully evaluated.

Templates are divided in three types:

  • Layout templates, responsible for the final rendering of a page, they must return text (page attribute set layout key).

  • Normal templates, responsible for preparing a page for the layout template, this kind of templates usually return a page attribute set (page attribute set template key).

  • Partial templates, includes that can be used in normal or layout templates.

The template evaluation flow is:

generatePage :: Page -> String
generatePage page = page.layout (page.template page)

Where:

  • page is a page attribute set.

  • page.template is a function taking the page attribute set, and returning an updated version of it (Page → Page).

  • page.layout is a function taking the page attribute set, and returning the page text source (Page → String).

This example consider templates environment already evaluated.

6.9.1. Text handling basics

Most of the work in template is done by manipulating text.

This section introduce the basics of text handling in the templates:

  • single-line or multi-line text (leading spaces are stripped without changing relative line align), delimited by ''.

    ''
      Hello world!
      Hello Styx!
    ''
  • single-line or multi-line text, delimited by ".

    "Hello world!"

Nix expressions can be included in text in enclosed in ${…​}.

Expression antiquotation
let name = "world"; in
"Hello ${name}!"

6.9.2. Layout templates

Layout templates are responsible for rendering the final source of a page.
A layout template function takes a template environment, and usually a page attribute set with a content attribute.

In a HTML context, the layout template is usually responsible of the HTML code that is not directly related to the content, like the html tag contents.

Layout template example
env:
page:
''
  <html>
    ...
  <body>
    ...
    ${page.content}
    ...
  </body>
  </html>
''
Layout templates are just functions, in case the normal template return the full page source like in a rss feed case, it is possible to set the page layout to the lib.id function. This will make the layout evaluation transparent and return the template result.

6.9.3. Normal templates

Normal templates are similar to the layout templates, with the only difference that their result will be evaluated by a layout template. A standard normal template will set or update the content attribute of a page attribute set so the layout template can produce the final source.

Normal templates can also add other attributes to the page attribute to fit any special need.

Example of a normal template
env:
page:
let
  content =
    ''
      <h1>${page.title}</h1>
    '';
in
  page // { inherit content; }
In some cases, it is useful to have the normal template to return the final source of the page.
By setting the page layout to the lib.id function, it is possible to bypass the layout template and have the normal template result being the final source source of the page.

This pattern of updating the page set content attribute and returning page set is so common that there is a normalTemplate function to abstract it.

Previous example abstracted with normalTemplate
{ lib, ... }:
lib.normalTemplate (page: "<h1>${page.title}</h1>")

6.9.4. Partial templates

Partials templates are templates that can be used in any other template.
They can be used as simple includes or to apply a template to a list of data.

6.9.5. Template environment

The template environment is the environment common to every template.
It is passed as the first parameter to every template function.

It is automatically set when the templates are loaded from a theme.

The default template environment consists in:

  • conf: The configuration attribute set.

  • lib: The library attribute set, it contains Styx and nixpkgs library functions.

  • templates: The templates attribute set.

  • data: The data attribute set.

  • pages: The pages attribute set.

The template environment is set in site.nix themes loading section and can be easily modified upon needs.
conf, lib are templates automatically set, but data and pages are explicitly set via the extraEnv argument of the load function.

Adding custom parameters to the template environment.
  /* Loading the themes data
  */
  themesData = styxLib.themes.load {
    inherit styxLib themes;
    extraEnv  = { inherit data pages; foo = "bar"; }; (1)
    extraConf = [ ./conf.nix extraConf ];
  };
1 Adding a foo variable to the template environment.

6.9.6. Template environment in templates

There are two ways of writing the template environment in the template, as a variable or as a deconstructed set.

Environment as a variable
env: (1)
page:
''
  ${env.conf.theme.site.title}
''
1 env is used as a set, and its key can be accessed with ..
Environment as a deconstructed set
{ conf, lib, ... }: (1)
page:
''
  ${conf.site.theme.site.title}
''
1 environment is deconstructed in its keys values. The last …​ means all others keys and is required if the set contains more keys than the keys deconstructed.

6.9.7. Calling templates in templates

It is possible to call templates in a template by accessing to the templates attribute of the template environment.

Calling a template in a template
{ templates, ... }:
page:
''
  ${templates.partials.head}
''
When templates are loaded, they will automatically receive the template environment as a parameter, this will partially evaluate the template function. This means that the template function will be become a single argument function (page).
Trying to call the current template will trigger an infinite loop and make the site generation fail.

6.9.8. Applying templates to multiple contents

The mapTemplate function can be used to map a template to a list of contents.

Applying a template to multiple contents
{ templates, ... }:
page:
''
  <ul>
  ${mapTemplate templates.post.list page.posts}
  </ul>
''

6.10. Combining Themes

In site.nix, themes are declared as a list. If multiple themes in the list provide the same file or template, the last theme in the list will be used.

This allows to build new themes based on other themes, like the showcase theme is built on the base of the generic-templates theme.

To combine themes, it is just needed to declare multiple themes in site.nix. If multiple themes define the same asset, asset from the latter theme in the list will be used.

Combining generic-templates and my-theme
themes = [
  styx-themes.generic-templates
  ./themes/my-theme
];

If generic-templates and my-theme both define templates/partials/content.nix, the one from my-theme will be used.
Any used asset that is not defined in my-theme will be used from generic-templates.

There is no limit in the number of themes that can be combined.

7. Data

Data refers to the data fetched or declared in the data section of site.nix.

Data is included in the default template environment and can be used in the pages section of site.nix to attach data to page attribute sets.

7.1. Creating data

Data can be created by directly defining a nix data structure.
An example of such usage is a navbar declared as a list of page attributes sets.

Creating navbar data
  data.navbar = [ pages.about pages.contact ];

7.2. Importing data

The styx data library provides functions to import external data:

  • loadFile: load a single data file and return it as an attribute set

  • loadDir: to load all the files in a directory and return them as a list of attributes sets (non-recursive)

The data loading functions return a set per file loaded and do a few things:

  • A fileData field is added that contains the file data as an attribute set with the following keys:

    • basename: The base name of the file.

    • ext: The extension of the file.

    • dir: The directory of the file.

    • name: The name of the file, basename and ext field combined with a ..

    • path: The path of the file.

  • Metadata is automatically parsed and merged to the set.

  • Data with introduction gain a intro attribute containing the introduction and the introduction is removed from the content.

  • Multipages data gain a pages attribute, a list containing each page content.

  • Converted markup is inserted in a content attribute.

  • Embedded nix expressions are evaluated.

  • If the file basename begins in a YYYY-MM-DD or YYYY-MM-DDThh:mm:ss format, this value will be inserted in a date attribute.

Nix data should be imported with the import function, that return the data in the nix file as it is.

7.3. Formats

This sections present the data file formats supported by styx.

7.3.1. AsciiDoc

AsciiDoc is a simple but complete markup language.

It is the format of choice for complex posts or pages as it has more functionalities than Markdown.

AsciiDoc example
= Lorem ipsum

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean dapibus aliquet justo ac lacinia.

The converted HTML will be in the content attribute of the data attribute set.

It is possible to add extra data to an AsciiDoc file by using Metadata.
Asciidoctor is used to convert AsciiDoc.

7.3.2. Markdown

Markdown is a lightweight markup language.

It is the format of choice for posts or pages as it allows to write content in a simple manner.

Markdown example
# Lorem ipsum

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean dapibus aliquet justo ac lacinia.

The converted HTML will be in the content attribute of the data attribute set.

It is possible to add extra data to a Markdown file by using Metadata.
MultiMarkdown is used to convert Markdown.

7.3.3. Nix

Nix expression language is the language used in site.nix and in every template.

It is a simple functional language and fits well data that has multiple fields.

Nix data
[
  { name = "Alice"; interests = [ "science" "writing" ]; }
  { name = "Bob";   interests = [ "sports" "reading" ]; }
]
It is possible to make nix data a function and pass arguments from site.nix such as lib for more flexibility.

Markup with metadata and nix data structures can be considered equivalent as it is possible to declare fields in nix data as markdown text, and markdown can declare nix fields as metadata.

Which one to choose is really a matter of choice but:

  • Nix is well suited for complex data structures with multiple fields.

  • Markup is well suited do content centric data.

7.4. Managing drafts

There a two main approaches to managing drafts with styx:

  1. Managing drafts with metadata.

  2. Managing drafts in a separate directory.

Using metadata is the recommended way as it is easier to set up.

7.4.1. Metadata

This is the recomended way to manage draft contents. Drafts and regular posts are in the same directory, but drafts have a draft metadata key set to true.

Mardown file marked as draft
---
draft: true
---
# Lorem ipsum

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean dapibus aliquet justo ac lacinia.

Then the list of posts can be fetched with loadDir by passing the renderDrafts parameter.

Fetching drafts
  data = {
    posts = loadDir { dir = ./data/posts; inherit (conf) renderDrafts; };
  };

To "publish" a draft, its draft metadata should be set to false, or removed.

If renderDrafts is not set, it will be assumed as false and automatically filter contents that have a draft metadata field set to true.

7.4.2. Directories

It is also possible to manage drafts in a separate directory. In this case optionals is used to load the drafts only if conf.renderDrafts is set to true.

  data = {
    posts  = let
      posts  = loadDir { dir = ./data/posts; };
      drafts = optionals (conf.renderDrafts) (loadDir { dir = ./data/drafts; draft = true; });
    in sortBy "date" "dsc" (posts ++ drafts);
  };

To "publish" a draft, the content file should be moved to the non draft directory.

7.5. Embedded nix

It is possible to embed nix expressions in markup files by surrounding them by {{ and }}.

Embedded nix in markdown
# Lorem ipsum

{{ toString (2 + 2) }}

The env parameter used in the loadFile or loadDir function is brought into scope, so lib functions or templates can be called.
This is specially useful to embed external media in content.

Calling a template in a markdown file
# Lorem ipsum

{{ templates.media.youtube { id = "YbUPdv03ciI"; } }}

{{ and }} can be escaped by prepending a \, \{{ and \}}, to prevent nix evaluation.

Asciidoctor automatically escape HTML. This feature can be disabled by surrounding the code with +++.

Calling a template in an asciidoc file
= Lorem ipsum

+++{{ templates.media.youtube { id = "YbUPdv03ciI"; } }}+++

7.6. Metadata

Metadata is the way to attach Nix data to markup files.

A metadata block is a yaml attribute set opened by --- and closed by ---.

Adding metadata to a markdown file
---
date: "2016-10-10"
tags: [ "foo" "bar" ]
---

# Lorem ipsum

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean dapibus aliquet justo ac lacinia.

Metadata attributes will automatically be added to the data attribute set.

7.7. Introduction

It is possible to declare a section on an imported markup file as the introduction.

Introduction and main contents are separated by [more] (asciidoc) or (markdown), content prior the separator will be inserted in the intro attribute of the data set.

Adding an introduction to a markdown file
Lorem ipsum dolor sit amet, consectetur adipiscing elit.

<!-- more -->

# Lorem ipsum

Mauris quis dolor nec est accumsan dictum eu ut nulla. Sed ut tempus quam, vel bibendum lacus. Nulla vestibulum velit sed ipsum tincidunt maximus.
intro field contents are included in the content field.

7.8. Multipage data

It is possible to split a markup file in multiple pages by using the <<< separator.

Splitting a markdown file in 3 pages
# Lorem ipsum

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean dapibus aliquet justo ac lacinia.

<<<

# Cras malesuada metus

Cras malesuada metus quis mi pulvinar faucibus. Vivamus suscipit est ante, ut auctor tortor semper nec.

<<<

# Phasellus consequat

Phasellus consequat a nibh sit amet ultricies. Quisque feugiat justo eu condimentum convallis.

The resulting data set will have an extra pages field that will hold the list of subpages content in format [ "…​" "…​" …​ ] in a pages attribute.

The data section is only responsible for generating the data attribute set. Transforming a data attribute set in a page attribute set is done in the pages section.
For example, the mkPagesList or mkMultipages function can generate pages from a multipage data set.

7.9. Taxonomies

7.9.1. Overview

Taxonomies are a way to group and structure data.

Styx taxonomies uses a two layers grouping system: taxonomies and terms.
The taxonomy layer groups the content declaring a specific data attribute, and the term layer groups the contents in the taxonomy depending on the values set to that specific attribute.

A common example of taxonomy is tags, tags will be the taxonomy and sports or technology will be the terms.

Taxonomy are organized in the following structure:

  • Taxonomy: Name of the grouping characteristic, for example tags.

  • Term: Groups in the taxonomy, for tags it will contain the values tags can take, for example sports or technology.

  • Values: Objects grouped by a taxonomy term, for example all the posts with the technology tag.

7.9.2. Creating a taxonomy data structure

A taxonomy data structure is created with the mkTaxonomyData function.
This function take a set parameter with two required attributes data and taxonomies.

taxonomies

A list of taxonomy fields to look for into data.

data

The list of attribute sets (usually pages attribute sets) to where the taxonomy field will be looked for.

Creating a taxonomy structure
  data.taxonomies = mkTaxonomyData {
                      data = pages.posts;
                      taxonomies = [ "tags" "categories" ];
                    };

This will generate a taxonomy data structure where:

  • tags and categories are taxonomies.

  • terms would be all the values of tags or categories set in pages.posts.

  • values would be all the pages in the pages.posts declaring tags or categories.

Then, the taxonomy related pages can be generated in the page section using the mkTaxonomyPages function.

This example uses the pages and not data attribute sets because data attribute sets do not have a path field making it impossible to generate links to them.
Using data attribute sets such as data.posts would make it impossible to generate pages from the taxonomy with mkTaxonomyPages.

The taxonomy data structure uses property lists, lists of attribute sets with a single key, for easier data manipulation.

Taxonomy data structure
[
  {
    TAXONOMY1 = [
      { TERM1 = [ VALUE1 VALUE2 ... ]; }
      { TERM2 = [  ... ]; }
      ...
    ];
  }
  {
    TAXONOMY2 = [
      { TERM1 = [ VALUE1 VALUE2 ... ]; }
      { TERM2 = [  ... ]; }
      ...
    ];
  }
]

7.9.3. Adding taxonomy to data

Adding taxonomy fields to a content requires adding a metadata attribute with a taxonomy name containing a list of terms.

Setting tags to a markdown file
{---
tags = [ "foo" "bar" ];
---}

# Lorem ipsum

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean dapibus aliquet justo ac lacinia.
Taxonomy terms must be a list of strings.

8. Pages

Pages are declared in a pages an attribute set. Every page or list of pages declared in this set will be generated.

8.1. Overview

Pages are passed to the generateFunction through the pageList argument that turn each page into a text file.

Pages are usually generated as HTML documents, but any kind of text file can be generated from a page attribute set.

8.2. The page attribute set

The page attribute set is an attribute set that must define at least three attributes:

  • layout: A function taking the template result as a parameter and returning the source of the file to generate.

  • template: A function taking the page attribute set as a parameter and returning an updated attribute set.

  • path: The path of the page to generate, must start with a /.

These attributes are the strict minimum, but many templates will require extra attributes like content or title.
path must start with a /, else site generation will fail.

Hello world! contains an example of a simple page attribute set.

Simple page attribute set
pages.index = {
  path     = "/index.html";
  layout   = template: "<html><body>${template}</body></html>";
  template = page: "<h1>Hello world!</h1>";
};

In an standard site.nix, template and layout would be attributes from the templates set like templates.page.full or templates.layout.

Page attribute sets are often augmented by various attributes or merged with data sets.

mkSite evaluates page.layout (page.template page) and outputs the result in page.path for every page in its pageList argument.
As many pages tend to use the same layout, the layout attribute is usually set in one go to all templates in the "site" section with pagesToList default parameter.
Usually, only pages that use a different layout explicitly declares it in pages.
The following examples will omit the layout attribute like often done in a normal site.nix.

8.3. Simple pages

Generating a simple page is trivial as it is just declaring the required attributes.

Creating an error 404 page
pages.e404 = {
  path     = "/404.html";
  template = templates.e404;
};
Attribute set attributes should not start with a number. That is why the 404 template is templates.e404 and not templates.404.
Nix allow to use attributes starting with a number, but they must be called by using ". This is error prone and not used in styx.

8.4. Attaching data to a page

Generating a page from an imported data is a very common case, and can be done with the // operator.

Attaching a data set to a page attribute set.
pages.about = {
  path     = "/about.html";
  template = templates.page.full;
} // data.about;

The // operator will merge the data.about data set in the pages.about page set.

8.5. Bypassing the layout

Pages, for which the template generates the full page source, like for RSS feeds, needn’t apply a layout. In such cases, the lib.id function, a function that return its parameter without changing it can be used as a "transparent" layout.

Using id as a layout
pages.feed = {
  path     = "/feed.xml";
  template = templates.feed.atom;
  items    = lib.take 10 posts;
  layout   = lib.id;
};
The id function is defined as x: x.

8.6. Split pages

Split pages refer to a list of data split though multiple similar pages.

A common example of split page is a blog archive page, where the posts are listed through multiple pages.

Split pages can be generated with the mkSplit or mkSplitCustom function.
mkSplit being a simpler version of mkSplitCustom function that should fit most of needs.

mkSplit example
pages.archives = lib.mkSplit {
  basePath     = "/archives";
  template     = templates.archives;
  itemsPerPage = 5;
  data         = pages.posts;
};

This will create a list of pages attribute sets with the following extra attributes:

path

Set accordingly to basePath. basePath.html for the first page, and basePath-i.html for the following pages where i is the index of the page.

items

The list of items for this page.

index

The position of this page in the list of split pages.

pages

The split pages lists, useful for generating a pagination.

For more complex splitting needs see the mkSplitCustom function documentation.

mkSplit only requires basePath, itemsPerPage and data as parameters. Any extra parameter passed will be added to every split page attribute set.
This is on purpose and is used in the previous example to set all the split pages template in the mkSplit declaration.

8.7. Multipages

Multipages are page attribute sets that have a pages attribute containing a list of pages in the pages attribute set.

Multipages are usually generated by importing Multipage data, data attribute set with a pages attribute.

8.7.1. Single page

Multipages can be generated with the mkMultiPages function.

mkMultipages example
pages.about = lib.mkMultipages ({
  template = templates.page.full;
  basePath = "/about";
} // data.about);
mkMultipages only requires basePath and pages as arguments. Any extra argument will be added to every generated attribute attribute set.

8.7.2. List of pages

For a list of content where single and multipages are mixed, mkPageList can be used.

Generating the page list with mutipage data
pages.posts = lib.mkPageList {
  data     = data.posts; (1)
  template = templates.post.full;
};
1 data is a list of data attribute set to generate pages attribute set from.

mkPageList will generate an attribute set with two attributes:

  • list: The list of contents, containing single pages and first page of multipages posts.

  • pages: List of all pages, including multipages subpages.

The list attribute can be used in archive or index pages, so multipages subpages will not be listed.

Using mkPageList list in a split page
pages = {
  index = mkSplit {
    title           = conf.theme.site.title;
    basePath        = "/index";
    itemsPerPage    = conf.theme.index.itemsPerPage;
    template        = templates.index;
    data            = pages.posts.list;
  };

  posts = lib.mkPageList {
    data     = data.posts;
    template = templates.post.full;
  };
}

8.8. Taxonomy pages

To see how to generate taxonomy data, refer to Taxonomies.

Taxonomy pages can be generated from a taxonomy data structure with the mkTaxonomyPages function.

taxonomies = lib.mkTaxonomyPages {
  data = data.taxonomies;
  taxonomyTemplate = templates.taxonomy.full;
  termTemplate = templates.taxonomy.term.full;
};

The mkTaxonomyPages function will create the following page attribute sets:

  • /TAXONOMY/index.html, the taxonomy index page set for every taxonomy. A terms attribute will be added to the page attribute set containing all the taxonomy terms.

  • /TAXONOMY/TERM/index.html, the term index page set for every term in every taxonomy. A values attribute will be added to the page attribute set containing all the values that use the term.

If required mkTaxonomyPages generated pages path can be changed with the taxonomyPathFun and the termPathFun, for details see mkTaxonomyPages.
If any of these functions is changed, the templates should be updated accordingly.

9. Site Generation

Site generation consists of a call to mkSite, and the preparation of its arguments.

Standard call to mkSite
pageList = pagesToList { inherit pages; }; (1)

site = mkSite { inherit conf files pageList; } (2)
1 Convert the pages attribute set to a list of pages.
2 Generate the site.

It is possible to set default attributes to every page set during the pages attribute by using the default argument of the pagesToList function.

A typical example is setting a default layout to every page set that do not declares one.

Setting a default layout to every page set
pageList = lib.pagesToList {
  inherit pages;
  default.layout = templates.layout;
};
Styx expects the site to be rendered in the site attribute of the main set.

9.1. Substitutions

Subtitutions are a way to pass variables from site.nix in markup or static files.

Substitutions are a set that is passed to the mkSite function. Any value of set will be replaced in the markup or static files that mkSite outputs.

Simple substitution set
  substitutions = {
    siteUrl = conf.siteUrl;
  };

  site = lib.mkSite {
    inherit files pageList substitutions;
  };

To be replaced, the variable as to be surrouded by @, for example @siteUrl@.

Using a substitution in a css file
.foo {
  background: url(@siteUrl@/images/foo.png);
}
Substitutions are specially useful for resolving in-site links with conf.siteUrl, but they can also be used with sass or less to externalize css variables in conf.nix.

9.2. Special files

Styx automatically converts SASS, SCSS and LESS files to css during site generation.

9.3. Hooks

mkSite provides two hooks to customize the site generation process:

  • preGen: A string or multiline string with shell commands to run before generating the site.

  • postGen: A string or multiline string with shell commands to run after generating the site.

9.4. Site derivation

Styx creates the static site as a standard nix derivation.

It is possible to set the derivation metadata by passing a meta set to the mkSite function.

Setting site derivation metadata
  site = with lib; mkSite {
    inherit files pageList substitutions;
    meta = {
      license = licenses.mit;
      name = "foo-1.0.0";
    };
  };

10. Multi-locale sites

While not being natively supported, Styx is flexible enough to generate multi-language sites.

For multi-locale sites, it is recommended to change site.nix structure to fit the locales. The following example is just a suggestion and should be adapted to needs:

The Fractalide website is an example of a fully multi-locale Styx site.

Multi-locale sites make it easy to mix namespaces.
Multi-locale site.nix
/*-----------------------------------------------------------------------------
   Init

   Initialization of Styx, should not be edited
-----------------------------------------------------------------------------*/
{ styx
, extraConf ? {}
}@args:

rec {

  /* Importing styx library
  */
  styxLib = import styx.lib styx;


/*-----------------------------------------------------------------------------
   Themes setup

-----------------------------------------------------------------------------*/

  /* Importing styx themes from styx
  */
  styx-themes = import styx.themes;

  /* list the themes to load, paths or packages can be used
     items at the end of the list have higher priority
  */
  themes = [
    styx-themes.hyde
  ];


  /* Loading the themes data for each locale
  */
  themesData = styxLib.mapAttrs (name: value:              (1)
    styxLib.themes.load {
      inherit styxLib themes;
      extraConf = [ ./conf.nix extraConf ];
      extraEnv = value;
    }
  ) locales;

  /* Bringing locale independent theme data to scope
  */
  inherit (themesData.eng) conf lib files env;             (2)


/*-----------------------------------------------------------------------------
   English

   This section declares English locale data and pages
-----------------------------------------------------------------------------*/

  locales.eng = rec {                                      (3)
    # Locale code
    locale = "eng";

    # Html lang
    html.lang = "en";                                      (4)

    # Prefix
    prefix = "";                                           (5)

    # Environment
    inherit (themesData."${locale}") env;                  (6)

    /*------------
      Data
    ------------*/
    data = with env; {                                     (7)
      # loading a single page
      about  = lib.loadFile { file = "${styx}/share/styx/scaffold/sample-data/pages/about.md"; inherit env; };
    };

    /*------------
      Pages
    ------------*/
    pages = with env; rec {                                (8)
      about = {
        path     = prefix + "/about.html";
        template = templates.page.full;
      } // data.about;
    };
  };


/*-----------------------------------------------------------------------------
   French

   This section declares French locale data and pages
-----------------------------------------------------------------------------*/

  locales.fre = rec {                                      (9)
    # Locale code
    locale = "fre";

    # Html lang
    html.lang = "fr";

    # Prefix
    prefix = "/${locale}";                                 (10)

    # Environment
    inherit (themesData."${locale}") env;

    /*------------
      Data
    ------------*/
    data = with env; {
      # loading a single page
      about  = lib.loadFile { file = "${styx}/share/styx/scaffold/sample-data/pages/about.md"; inherit env; };
    };

    /*------------
      Pages
    ------------*/
    pages = with env; rec {
      about = {
        path     = prefix + "/about.html";
        template = templates.page.full;
      } // data.about;
    };
  };

/*-----------------------------------------------------------------------------
   Site

-----------------------------------------------------------------------------*/

  /* converting pages attribute set to a list
  */
  pageList = lib.localesToPageList {                      (11)
    inherit locales;
    default = locale: {
      layout  = locale.env.templates.layout;
    };
  };

  /* Generating the site
  */
  site = lib.mkSite { inherit files pageList; };

}
1 Load the themes for each locale. The themes are loaded for each locale to ensure the theme env is using the correct data and pages.
2 Put locale independent theme data to the main scope. env is exported to the main namespace to ensure styx site-doc works well.
3 The English locale attribute set, holds the pages and data set and any other required attribute. This set attributes are merged in the theme env.
4 If the generic templates theme is used, html.lang in the environment will be used to set the lang attribute of the html tag ensuring the correct locale is declared.
5 Prefix is used on the pages set, and prepended to every pages path. For the default language, prefix should be an empty string.
6 Inherit the theme data environment for the current locale.
7 English locale data set.
8 English locale pages set.
9 The French locale attribute set.
10 French locale pages prefix.
11 The page list generated by combining every locale pages.
This example uses ISO-639-3 language codes, but any format can be used.

10.1. Using a different configuration per locale

The previous example uses the same conf.nix for every locale. In some cases, it can be useful to use a different conf.nix per locale.
This can be easily achieved by changing the theme loading section in the following manner:

  /* Loading the themes data for each locale
  */
  themesData = styxLib.mapAttrs (name: value:
    styxLib.themes.load {
      inherit styxLib themes;
      extraConf = [ ./conf."${name}".nix extraConf ];    (1)
      extraEnv = value;
    }
  ) locales;
1 By changing ./conf.nix to ./conf.${name}.nix, each locale will use a separate configuration file, eg: conf.eng.nix, conf.fre.nix, …​

10.2. Translating strings in templates

To translate strings in templates, e.g. Read more, a custom theme library with an i18n function can be used:

themes/THEME_NAME/lib.nix
{ lib }:
with lib;
{
  i18n = text: locale:
    let translations = {
      "Read More" = {           (1)
        jpn = "続きを読む";
        fre = "Lire la suite";
      };
    };
  in attrByPath [ text locale ] text translations;
}
1 Strings to translate shoule be defined as an attribute set, the attribute name being the string used in the template and the value an attribute set in format { LOCALE = "TRANSLATION"; };.
Example of usage in a template
{ lib, locale, ... }:                  (1)
with lib;
''<p>${i18n "Read More" locale}<p>''   (2)
1 locale comes from site.nix extraEnv and is the ISO-639-3 code of the locale in the example.
2 Call i18n to translate the string.
i18n stands for internationalization.

11. Debugging

The nix-repl utility can be used to debug a styx site.
It can be installed with nix-env or used in a temporary environment with nix-repl.

Starting nix-repl in a nix-shell
$ nix-shell -p nix-repl --run 'nix repl "<nixpkgs>"'

11.1. Inspecting site.nix attributes

Inspecting the conf configuration set
$ nix repl "<nixpkgs>"

nix-repl> site = callPackage (import ./site.nix) {}

nix-repl> site.conf
{ siteUrl = "https://styx-static.github.io/styx-theme-showcase"; theme = { ... }; }

11.2. Using lib functions

Using parseDate
$ nix repl "<nixpkgs>"

nix-repl> site = callPackage (import ./site.nix) {}

nix-repl> with (site.lib.parseDate "2016-05-18T12:40:21"); "${date.lit}, ${time}"
"18 May 2016, 12:40:21"

11.3. Rendering a page source

Rendering a page source
$ nix repl "<nixpkgs>"

nix-repl> showcase = callPackage (import "${(import styx.themes).showcase}/example/site.nix") {}

nix-repl> with showcase; lib.generatePage (pages.about // { layout = templates.layout; }) (1)
"<!DOCTYPE html>\n<html lang=\"en\">\n\n<head>\n  <meta charset=\"utf-8\">...."

nix-repl> with showcase; templates.layout (templates.page.full pages.about) (2)
"<!DOCTYPE html>\n<html lang=\"en\">\n\n<head>\n  <meta charset=\"utf-8\">...."
1 Rendering a page with the generatePage function.
2 Rendering a page by running directly layout (template page).

11.4. Building a site

It is possible to generate the site in the nix store from nix-repl.

Building a site
$ nix-repl "<nixpkgs>"

nix-repl> showcase = callPackage (import "${(import styx.themes).showcase}/example/site.nix") {}

nix-repl> :b showcase.site
...
this derivation produced the following outputs:
  out -> /nix/store/ak6h49a9h7asysv91nf31nhd5h7fgzhi-styx-site

12. Deployment

12.1. GitHub pages

Styx supports basic deployment to GitHub pages.

This is a two step process:

  • first by preparing the repository to deploy on GitHub pages. (deploy --init-gh-pages)

  • then by updating that branch. (deploy --gh-pages)

12.1.1. Initialization

The styx deploy --init-gh-pages command will prepare the repository for GitHub deployment. This command will do the following:

  • create a gh-pages directory

  • add the gh-pages folder to .gitignore

  • clone the repository in the gh-pages folder

  • create a new empty gh-pages branch in the gh-pages folder

12.1.2. Update the gh-pages branch

The styx deploy --gh-pages command will build the site, and update the gh-pages folder with the generated static site and commit it to the gh-pages branch.

Then changes can be pushed with the following commands:

$ (cd gh-pages && git push -u origin gh-pages) (1)
$ git push -u origin gh-pages (2)
1 Push the gh-pages folder gh-pages branch to the root repository.
2 Push the root repository gh-pages branch to the remote repository.

12.2. NixOps

NixOps is a deployment tool for NixOS configurations, and can be used to deploy styx sites.

NixOps expression to deploy a styx website
{
  network.description = "Styx example";

  webserver = { config, pkgs, ... }: { (1)
    deployment = { (2)
      targetEnv = "virtualbox";
      virtualbox.memorySize = 1024;
      virtualbox.headless = true;
    };

    networking.firewall.allowedTCPPorts = [ 80 ]; (3)

    services.nginx = { (4)
      enable = true;
      httpConfig = ''
        server {
          listen 80;
          location / {
            root ${(pkgs.callPackage ./site.nix {}).site}; (5)
          }
        }
      '';
    };
  };
}
1 Create a machine named webserver for deployment.
2 Set up deployment information, for this example deploy on a VirtualBox machine.
3 Open port 80 on the webserver machine.
4 Nginx settings.
5 Set the Nginx root location to the styx site package. Remote repositories can be fetched with nixpkgs fetch* functions.
The NixOps manual provides information about all the deployment options.

Then the site can be deployed via NixOps with the following set of commands:

$ nixops create -d styx-site nixops-expression.nix (1)
$ nixops deploy -d styx-site (2)
1 This command creates a new NixOps deployment, the -d flag specify the deployment name.
The deployment information can be queried with the nixops info -d styx-site.
nixops-expression.nix is a file containing the nix expression for the deployment like the one showed in the example.
2 This command will create the VirtualBox machine and deploy the configuration into it.
If all goes well, the website will be available by opening the deployment machine in a browser. The deployement machine IP can be found with the nixops info -d styx-site.

12.3. Amazon S3 Bucket

Amazon S3 buckets can be used to host static websites. The AWS CLI tool can be used in conjunction with styx to upload a styx website to a S3 bucket.

Deploying a styx website to S3
$ nix-shell -p awscli

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

Site url can also be specified with the --site-url flag.

Deploying a styx website to S3 using a custom site-url
$ nix-shell -p awscli
$ aws s3 sync $(styx store-path --site-url "http://<bucket name>.s3-website-<region>.amazonaws.com") s3://<bucket name>/
For a S3 website to be world accessible, adjusting policies might be required.

12.4. Other

Styx does not yet provide a universal deployment method, but rsync can be used to deploy a Styx site to a remote server via ssh.

13. Command line interface

The Styx provides a command line program styx.

13.1. Generic flags

styx --help

Display the help message.

styx --version

Display the version.

13.2. Common flags

--in DIR

Run the command in DIR.

--file FILE

Use FILE instead of site.nix.

--drafts

Process and render drafts.

--show-trace

Show debug output when styx command fails. (Nix flag)

--arg NAME VALUE

Pass an argument NAME to site.nix main function.

--argstr NAME VALUE

Pass a string argument NAME to site.nix main function.

-I PATH

Add PATH to to the Nix expression search path, useful to use custom versions of nixpkgs.

13.3. New

The new command is used to create a site or a theme.

13.3.1. Site

The new site command is used to create a new Styx site.

styx new site NAME

Create a Styx site in NAME directory in current path.

styx new site NAME --in DIR

Create a Styx site in DIR/NAME.

13.3.2. Theme

The new theme command is used to create a new theme.

styx new theme NAME --in DIR

Create a theme skeleton in DIR/NAME.

13.4. Build

The build command is used to build a Styx site.

styx build

Build the Styx site and write the output in the public directory.

styx build --out DIR

Build the nix site and write the output in the DIR directory.

The nix-build --show-trace, --arg NAME VALUE, --argstr NAME VALUE and -I PATH flags can be used with the build command.

13.5. Store path

The store-path command is used to build a Styx site in the nix store and return the store path.

styx store-path

Build the Styx site in the nix-store and return the full store path..

The nix-build --show-trace, --arg NAME VALUE, --argstr NAME VALUE and -I PATH flags can be used with the store-path command.

13.6. Preview

The preview command is used to launch a server that will listen on localhost (127.0.0.1) port 8080 by default. The preview command will override conf.siteUrl to preserve links.

The server can be stopped by pressing Ctrl+C.

styx preview

Start a preview server on 127.0.0.1:8080.

styx preview --port 9090

Start a preview server on 127.0.0.1:9090.

styx preview --port 9090 --drafts

Start a preview server on 127.0.0.1:9090 with drafts rendered.

Drafts are rendered only if the related logic is present in site.nix. The --drafts flag just make styx pass extraConf.renderDrafts as true to site.nix.

13.7. Preview theme

The preview-theme command is used to launch a server that will listen on localhost (127.0.0.1) port 8080 by default and preview the selected theme bundled with styx.

The server can be stopped by pressing Ctrl+C.

styx preview-theme generic-templates

Start a preview server for the generic-templates theme on 127.0.0.1:8080.

styx preview-theme generic-templates --port 9090

Start a preview server for the generic-templates theme on 127.0.0.1:9090.

styx preview-theme generic-templates --port 9090 --drafts

Start a preview server for the generic-templates theme on 127.0.0.1:9090 with drafts rendered.

13.8. Theme path

The theme-path command is used to print the store path a a theme from the styx-themes.

styx theme-path generic-templates

Print the store path for the generic-templates theme.

13.9. Live

The live command is similar to preview, with the unique difference that the site is automatically rebuilt when a change is made.

The live mode should be quitted by pressing q.

styx live

Start a live preview server on 127.0.0.1:8080.

styx live --port 9090

Start a live preview server on 127.0.0.1:9090.

styx live --port 9090 --drafts

Start a live preview server on 127.0.0.1:9090 with drafts rendered.

The live mode does not automatically reload the browser.
If the live mode is not quitted by pressing q, there is a possibility that the server process will stay alive in background. The server process can be found by running ps aux | grep caddy and killed with the kill command.

13.10. Linkcheck

Run linkchecker on the site. Checks if the liks are valid.

styx linkcheck

Check site links and print a report.

13.11. Serve

The serve command is used to build a site and launch a local server. This allow to check the site without having to deploy it. The server can be stopped by pressing Ctrl+C.

styx serve

Will serve on the localhost on port 8080.

styx-serve --port 9090

Will serve on the port 9090.

styx serve --detach

Will serve on the localhost on port 8080 and run the server on background, process can be found by running ps aux | grep caddy.

The nix-build --show-trace, --arg NAME VALUE, --argstr NAME VALUE and -I PATH flags can be used with the serve command.
Styx uses the caddy server, even if it is a performant server, styx serve launches it without any special settings.
For production environments it is recommended to use a carefully configured server over styx serve.

13.12. Doc

The doc command can be used to launch styx HTML documentation in the default browser ($BROWSER).

styx doc

Open the HTML help in the default browser.

BROWSER=firefox styx doc

Open the HTML help in firefox.

On macOS, run BROWSER=open styx doc to use the default browser.

13.13. Site-doc

The site-doc command can be used to generate and launch in the default browser a documentation for a styx site.

styx site-doc

Open the HTML help in the default browser.

BROWSER=firefox styx site-doc

Open the HTML help in firefox.

On macOS, run BROWSER=open styx site-doc to use the default browser.

13.14. Gen-sample-data

The gen-sample-data command can be used to generate sample data, useful for creating themes example sites.

styx gen-data

Generate sample data in ./data.

13.15. Deploy

The deploy command is used to deploy a styx site on a remote server. Currently only GitHub pages are supported.

For more details see the Deployment section.

styx deploy --init—​gh-pages

Prepare a git repository to be able to deploy on GitHub pages.

styx deploy --gh-pages

Commit the Styx site in the current directory to the gh-pages branch in the ./gh-pages folder.

styx deploy --gh-pages --in ./example --repo ./

Commit the Styx site in ./example to the gh-pages branch in the ./gh-pages folder.

14. Release Notes

Styx 0.7.5 - 2022/08/17

Highlights:

  • Cleanup the codebase via a new site.nix & conf.nix interface

  • Implemet a new frontmatter parser for markdown & asciidoc

Breaking Changes:

Metadata

The metadata format is now normal frontmatter written in yaml between opening and closing --- at the beginning of the file.

Furthermore, intro is no more separated by >>>, but for markwdown with <!-- more -→ and for asciidoc with [more].

Pre 0.7.5 frontmatter
{---
draft = true;
---}
Post 0.7.5 frontmatter
---
draft: true
---
Site Loading

site.nix format have been simplified. Required arguments are now pkgs and extraConf. conf.nix format now receives, both, lib & pkgs.

The site loading mechanism has changed, see the comparison below.

Pre 0.7.5 conf.nix
{ lib }:
Post 0.7.5 conf.nix
{ lib, pkgs }:
Pre 0.7.5 site.nix
{ styx
, extraConf ? {}
}:

rec {

  /* Importing styx library
  */
  styxLib = import styx.lib styx;


  /* Importing styx themes from styx
  */
  styx-themes = import styx.themes;

  /* list the themes to load, paths or packages can be used
     items at the end of the list have higher priority
  */
  themes = [
  ];

  /* Loading the themes data
  */
  themesData = styxLib.themes.load {
    inherit styxLib themes;
    extraEnv = { inherit data pages; };
    extraConf = [ ./conf.nix extraConf ];
  };

  /* Bringing the themes data to the scope
  */
  inherit (themesData) conf lib files templates env;
Post 0.7.5 site.nix
{ pkgs ? import <nixpkgs> {}
, extraConf ? {}
}:

rec {

  styx = import pkgs.styx {
    # Used packages
    inherit pkgs;

    # Used configuration
    config = [
      ./conf.nix
      extraConf
    ];

    # Loaded themes
    themes = let
      styx-themes = import pkgs.styx.themes;
    in [
      # Declare the used themes here, from a package:
      #   styx-themes.generic-templates
      # Or from a local path
      #   ./themes/my-theme

    ];

    # Environment propagated to templates
    env = { inherit data pages; };
  };

  # Propagating initialized data
  inherit (styx.themes) conf files templates env lib;

Styx 0.7.2 - 2020/06/02

Fixes

  • caddy fails with no bin, removing the .bin fixes it

  • proofreading

Styx 0.7.1 - 2018/01/26

Fixes

  • Fixed styx command path resolution when styx was installed globally.

Styx 0.7.0 - 2017/08/26

Highlights:

  • Styx use its own version without relying on global <nixpkgs>, this ensure that site.nix format, used styx-themes and styx versions are matching.

  • Instructions and helpers for multi-locale sites.

  • Block feature for flexible single page websites, used in the Agency theme.

  • Better support for Darwin platforms.

New themes:

  • Nix

  • Ghostwriter

New commands:

  • styx preview-theme: Preview a styx-theme theme, eg: styx preview-theme ghostwriter.

Breaking Changes:

site.nix format have been simplified. Required arguments are styx and extraConf only. The themes set styx-themes, can be accessed with import styx.themes and is tied to the styx version.

Pre 0.7.0 site.nix
{ lib, styx, runCommand, writeText
, styx-themes
, extraConf ? {}
}@args:

rec {

  /* Importing styx library
  */
  styxLib = import styx.lib args;
Post 0.7.0 site.nix
{ styx
, extraConf ? {}
}:

rec {

  /* Importing styx library
  */
  styxLib = import styx.lib styx;


  /* Importing styx themes from styx
  */
  styx-themes = import styx.themes;

Styx 0.6.0 - 2017/02/26

Highlights:

  • Nix expressions can be embedded in markup files.

  • Site building perfomance improvements.

New commands:

  • styx site-doc: generate documentation for a styx site.

  • styx gen-sample-data: generate sample data.

  • styx linkcheck: check the internal links of a site.

New features in the generic templates theme:

  • templates.media.*: For embedding media. (giphy, github gists, slideshare, speakerdeck, twitter, vimeo and youtube)

  • conf.services.*: For third party services integration. (disqus, piwik and google analytics)

  • conf.lib.*: highlightjs, google fonts and mathjax support added.

Improvements

  • Performance.

  • Drafts can be automatically handled with metadata.

  • mkPageList automatically handle multipage pages.

  • Themes and library documentations.

Breaking Changes:

  • Substitutions in data files have been removed in favor embedded nix. (substitutions can still be used in static files)

  • themes.load function arguments were renamed:

    • templates.extraEnv renamed to extraEnv.

    • conf.extraConf renamed to extraConf.

  • loadDir and loadFile functions arguments have changed.

  • mkMultiTail function have been removed in favor of mkPageList.

  • loadDir and loadFile functions arguments has been modified.

  • generateSite was renamed to mkSite and its pagesList argument was renamed to pageList.

  • mkPageList now outputs a pages set, with a list attribute containing the page list. To refer pages generated with mkPageList use the list attribute, eg pages.posts.list.


Styx 0.5.0 - 2017/01/18

Highlights:

Breaking Changes:

  • Many, among others:

    • site.nix was refactored

    • Themes theme.nix was removed, its functionality is divided in two files, conf.nix and meta.nix. conf.nix for configuration interface and meta.nix for theme metadata.

    • Themes meta.nix file must be present and must declare a id attribute specifying the theme id.

    • lib.pages.setDefaultLayout was removed (default pages values can be set with the default argument of [lib.generation.pagesToList]).

    • all occurences of href in function names / parameters and template variables has been replaced with path, pages path attribute must start with a /.

Upgrading:

This release brings many incompatible changes that requires to refactor site.nix to upgrade.
Changes involve, among others, the init section of site.nix, site.nix returning a set instead of a generateSite call and href occurrences replaced by path (path attributes must start with a /).

Comments:

This is the first close to stable release of styx. Please test and send any bug or question to the bug tracker.


Styx 0.4.0 - 2016/12/07

Highlights:

  • Better integration with the Nix ecosystem, styx sites can be called from nix expressions with callPackage

  • Themes can be used from the styx-themes set of packages

  • new manual subcommand to open the HTML documentation in a browser

Breaking Changes

  • Removal of the state variable in site.nix

  • site.nix init section was refactored

This release brings few major breaking changes that make upgrading from 0.3.0 non trivial.
The main changes involve the init section of site.nix.


Styx 0.3.0 - 2016/10/26

Highlights:

This release brings many major breaking changes that make upgrading from 0.2.0 non trivial.
Fortunately, the new features introduced in this release should make future upgrades easy.


Styx 0.2.0 - 2016/10/10

Highlights:

New features:

  • cli command

  • new preview subcommand to preview a site locally

  • new live subcommand to preview and automatically reload changes

  • serve subcommands new flags:

  • --detach to launch the server in a background process

  • --server-host to specify the server listening hostname

  • --siteUrl to override conf.siteUrl

  • new -target flag to specify the Styx site folder

  • content substitutions (Substitutions)

  • themes (Themes)

  • metadata (Metadata)

  • 404 error page template

Incompatible changes:

  • default.nix was renamed to site.nix

  • site.nix previewMode was renamed to renderDrafts

  • cli --preview flag has been renamed to --drafts

  • lib.content: getPosts, getDrafts and parsePage arguments have changed

  • lib.generation: generateSite arguments have changed

  • lib.utils: loadTemplateWithEnv function was removed

Bug Fixes:

  • nix link in the default theme layout template

  • styx new is working when called in empty folders

  • default theme archive title is not hardcoded

  • default them pagination is displayed only when there is more than one page

This release bring many major changes that make updating from 0.1.0 non-trivial.

To update, it is recommended to generate a new site, create a new theme with customized templates and static files, and update site.nix accordingly.


Styx 0.1.0 - 2016/10/07

Initial release of Styx.

Appendix A: Styx-themes

Appendix B: Library