How does soupault compare to other static site generators?

Like Hugo or Zola, soupault is available as a single self-contained executable (~17MB), so it’s trivial to install and upgrade, and will not break easily.

Like Jekyll or Nikola, it’s extensible with a scripting language and allows plugins to redefine its built-in features.

Unlike any other SSG, it works on the HTML element tree level. This means that it:

For details, check out the comparison table.

What markup languages/Markdown flavors does soupault support?

The only built-in supported format is HTML. However, you can automatically import pages in any format if you install and configure a convertor for it.

For example, if you want *.md files to be processed with Pandoc in CommonMark mode:

  md = 'pandoc -f commonmark+smart -t html'

You can specify as many preprocessors as you want.

Do I need to change my website to start using soupault?

Not necessarily. With many other website generators, you need to create a theme/template in their own format to start using them. However, soupault can work also as an HTML processor for existing websites, so it’s much easier to give it a try.

Is soupault just an HTML processor?

No. It has an HTML (post-)processor mode and some projects use it as such because it’s pretty much the only tool that can do that.

However, it can also do what all other SSGs do: assemble pages, extract metadata from them, and render that metadata on index pages. That’s not counting its ability to also manipulate pages in completely arbitrary ways that other SSGs do not support.

Is soupault “blog-aware”?

Soupault does not have a built-in content model. Instead, it allows you to define your own. You can make a blog, a wiki, or anything else you want.

If you want to quickly start a blog with soupault, you can use the soupault-blog application. It comes with a blog content model and relevant plugins (post reading time, Atom feeds…) ready to use.

Is soupault fast?

It’s subjective, but here are some tests I once ran on an 8th gen Intel NUC machine: i5-8259U, SSD, Fedora 35, NVMe SSD. 1

Assembling 1000 HTML pages (~4kbytes each) takes ~2s (with verbose = true) or ~1.6s (with progress logging disabled).

If you add an external Markdown preprocessor (I tested with cmark --smart --unsafe), it takes ~3.5s in the verbose mode or ~3.2s with logging disabled.

All in all, the UNIX-way approach with delegating some processing steps to external programs does have its cost, but for all but the largest websites it’s not going to be a problem.

Are there themes?

The problem with typical SSG/CMS “themes” is that they aren’t really themes—most often they contain a mix of formatting, styling, and logic. Essentially, they are applications written on top of a framework.

One reason why many SSG frameworks rely heavily on theme catalogs is that writing a working website from scratch is not trivial. The reason for that is heavy use of templates that are by definition a mix of presentation and logic.

Working at the HTML element tree level allows soupault to decouple the logic from presentation to a much greater extent, so it needs themes less.

However, there are some ready to use blueprints, such as blog..

Does soupault use a template processor?

Soupault does not use a template processor for assembling pages from a “theme” and a content file. That is done by inserting the content into an element specified by a CSS selector.

However, it does have a built-in template processor (jingoo) and one of the options for rendering the site index is to supply a template. You can also call template rendering from Lua plugin code.

Are the shortcodes?

No. Instead, soupault allows you to write “fake” HTML elements and make them real via HTML transformation plugins.

It can be as simple as translating <wikipedia lang="en">HTML</wikipedia> to <a href="https://en.wikipedia.org/wiki/HTML>HTML</a> or much more complex, e.g. you can create hyperlinked glossaries. See examples in the Augmented HTML plugin catalog category.

Using soupault

How to set up a basic project

Run soupault --init in an empty directory. It will create the following directory structure and files:

├── site
│   └── index.html
├── soupault.toml
└── templates
    └── main.html

The site/ directory is where your page content files go. The templates/main.html file is the page template. Thesoupault.toml file is the configuration file for soupault, in the TOML format.

If you run soupault in that directory, it will build your website and place generated pages in the build/ directory. You can then deploy your website with any tool of your choice, like neocities push, rsync, or anything else.

Do I need to keep everything in one directory?

No. It makes things easier, but it’s not required. By default, soupault will look for soupault.toml in the current working directory and read it. From there it will take the site_dir and build_dir options. You can use absolute paths for those options.

You can also override the locations of the config file and the source/output directories from the command line. A UNIX example of overriding everything at once:

SOUPAULT_CONFIG="/tmp/mysite.conf" soupault --site-dir ~/mysite --build-dir ~/public_html

On Windows, there’s no easy way to set an environment variable for a command like that, so you can use a command-line option to specify the config file (since 4.2.0):

soupault --config A:\mysite.cfg --site-dir B:\mysite --build-dir C:\inetpub\wwwroot\

Note that --config, --site-dir and --build-dir options are available and work the same on all platforms, so on UNIX-like systems the choice between --config and SOUPAULT_CONFIG environment variable is up to the user.

How to add assets (pictures, CSS...)

You can just drop files in the site/ directory together with pages. Files with extensions matching the settings.page_file_extensions option are considered pages and processed, by default that’s ["html", "htm", "md", "rst", "adoc"]. All other files are just copied to the build/ directory unchanged.

How to create a site section?

Just create a subdirectory in site/. Every subdirectory automatically becomes a section, e.g. site/pictures/cats.html becomes build/pictures/cats/index.html if clean URLs are enabled, or build/pictures/cats.html if they are disabled.

They can be nested as deep as you want, there is no depth limit. However, section index pages is your responsibility, so if you want https://example.com/pictures to work, you should also add site/pictures/index.html.

Soupault can be configured to generate a list of all pages in a section, but there still must be a section index page, whether you are maintaining a list of pages in the section by hand or using a script to generate it.

How to disable clean URLs?

Soupault uses “clean URLs” by default. This means a page like site/about.html turns into build/about/index.html, so that on a deployed website it can be accessed as http://example.com/about.

For a new website, the choice between /about/ and /about.html is purely aesthetic, but for people who already have a website and want to switch to managing it with soupault, it can be a real show-stopper since it can break all their links. For this reason, soupault has a settings.clean_urls option. Use clean_urls = false if you want to disable them.

With clean_urls = false, soupault preserves file names exactly, e.g. site/about.htm becomes build/about.htm, and site/projects/soupault.html becomes build/projects/soupault.html.

Where the page content goes?

When soupault builds your website, it takes the empty page template from templates/main.html, reads content from files in site/ such as site/about.html, and inserts it in the template.

By default, it will insert the page content into the <body> element of the page template. However, you can insert page content into any element using the settings.default_content_selector option.

Suppose you want your page content to go to <div id="content">. Then add that div to templates/main.html, find that option in soupault.toml, and set settings.default_content_selector = "div#content".

How to create a page with unique layout?

Using a template saves time and allows easily changing the website layout. However, what if you want to make a page with a unique layout different from the template?

Soupault decides whether to use a template or not by checking if a page file has an <html> element in it. It it does not have it, then the file is considered a page body and inserted in the template. If it does, then it’s considered a complete page and only processed by widgets/plugins.

So, to make a unique page, just make it a complete HTML document.

How to automatically set page title?

A website where every page has the same <title> is a sad sight. Soupault can set the page title from an element of your choice. This is the config for this page, that takes the title from an element with id="title". In this page it’s a <h1>, but it could be anything.

  widget = "title"
  selector = "#title"
  default = "soupault"
  append = " &mdash; soupault"

How to add a table of contents?

Soupault can automatically generate tables of contents from heading tags. This is the config for this very page:

  widget = "toc"
  selector = "#generated-toc"

  min_level = 2

  toc_list_class = "toc"
  toc_class_levels = false

  numbered_list = true

  heading_links = true
  heading_link_text = "→ "
  heading_link_class = "here"

  use_heading_slug = true

Remember to add a <div id="generated-toc"> to templates/main.html if you want a ToC in every page, or just to pages where you want it.

How to add footnotes?

If you like footnotes, you can add them to your pages easily. This is the config for this website:

  widget = "footnotes"
  selector = "div#footnotes"
  footnote_selector = ".footnote"
  footnote_link_class = "footnote"
  back_links = true
  link_id_prepend = "footnote-"
  back_link_id_append = "-ref"

It assumes that there’s a <div id="footnotes"> in the page. If you forget to include it in the page, footnotes will not appear.

It considers elements with class="footnote" footnotes and moves them to that div. The back_links option creates links back from footnotes to their original locations, you can set it to false if you only want forward links.


Is it safe to run soupault on untrusted data?

No, it isn’t safe.

Soupault allows executing system commands from the config and from plugins, so you should exercise caution if you want to run soupault on anything you didn’t write. You should either run it sandboxed or thoroughly inspect the config and plugins to make sure they aren’t doing anything malicious.

Is there a safe mode?

No, there isn’t.

A “safe mode” that disallows execution of external commands would limit soupault’s usefulness because being able to bring external tools to its workflows is one of the main design points.

There is no reliable way to automatically determine what is safe and what isn’t and as long as there is a way to execute one external program and pass data to it, there’s likely a way to execute anything.

If you want to run soupault on untrusted data, use your operating system’s isolation capabilities (virtual machines or containers).

Edge cases

What happens if you have a directory and a page with the same name?

Don’t do it. It’s undefined behaviour and anything may happen.

Currently, if you have clean URLs enabled and there are both site/test.html and site/test/index.html, then the latter will be used. But it just happens to be this way now and may change any time, so don’t count on it.

What happens if I load a plugin with the same name as a built-in widget?

The plugin wins. You also get a log message that clarifies that.

This is an intentional choice, so that people can replace built-in functionality with plugins if they want to.

1Those figures are for “warm” builds (pages cached in RAM), but the initial build takes maybe a couple of ms longer. For machines with magnetic drives reading pages from disk may take longer.