fssg

Blazing Fast. Pure Shell. Zero Fuss.

A minimal, blazing fast static site generator built entirely with POSIX shell. Transform Markdown and HTML into a complete statically built website with powerful features, no complex dependencies.

Why Choose fssg?

Radical Simplicity. Run Anywhere.

With zero dependencies beyond a standard POSIX shell, fssg is the ultimate portable generator. No Node.js, no package manager, no complex toolchain. Just your content and a single script.

.
├── fssg
└── src
    ├── index.md
    └── template.html

Pure Shell, Peak Performance.

By leveraging the raw power of shell and optimized `awk` scripts, fssg builds sites at incredible speeds. Parallel processing is built in, allowing you to scale to hundreds of pages without the wait. Instantaneous builds become the norm.

./fssg -j 100

Everything You Need, Nothing You Don't.

A complete development workflow is included out-of-the-box. The built-in file watcher, dev server, and automatic browser opening provide a modern, seamless experience without any external tools.

./fssg -j 100 -s -w -o

Quick Start Guide

1

Setup Your Project

You can either download just the script or clone the entire repository if you want the optional mongoose dev server.

Option A: Download only the fssg script.

wget https://raw.githubusercontent.com/xlc-dev/fssg/main/fssg
chmod +x fssg

Option B: Clone the full project, then grab just the mongoose folder and the fssg script.

git clone https://github.com/xlc-dev/fssg.git
mkdir mysite
cd mysite

cp ../fssg/fssg .
cp -r ../fssg/mongoose .
2

Create Content

Create a master template.html and your first page, index.md. fssg will inject the content from `index.md` into the template.

src/template.html:

<!DOCTYPE html>
<html>
<head>
  <title>{{title}}</title>
</head>
<body>
  {{content}}
</body>
</html>

src/index.md (or use html):

# Hello, World!

This is my first page built with fssg.
3

Build & Preview

Run the development command. This builds the site, starts a server, watches for changes, and opens your browser.

./fssg -j 100 -s -w -o

Your new site is now running at http://localhost:8000! For a deep dive into all features, see the documentation below.

Features Deep Dive

  • CLI
  • Directory Structure
  • Templating
  • Content & Assets
  • Conditionals
  • Post Listings

Command-Line Interface

The fssg script is controlled via command-line flags.

./fssg [options]
  • -h, --help: Display the help message and exit.
  • -q, --quiet: Suppress all informational output, showing only errors. Overrides -v.
  • -v, --verbose: Show detailed per-file processing information.
  • -n, --nocolor: Disable colored terminal output.
  • -w, --watch: After the initial build, watch the src/ directory for changes and automatically trigger a rebuild.
  • -s, --serve: Start a local web server for the dist/ directory on port 8000. Requires the mongoose/ binaries.
  • -o, --open: Automatically open a web browser to the local server address. Only works when -s is also used.
  • -j <number>: Set the number of parallel build jobs to run. Defaults to 4. Increase for faster builds on multi-core systems.

Project Structure

fssg expects a specific directory layout to function correctly. This forces the same structure everywhere, making it easier to switch between different projects.

.
├── fssg
├── mongoose/
│   ├── mongoose_linux
│   ├── mongoose_mac
│   └── mongoose_windows.exe
└── src/
    ├── includes/
    │   └── footer.html
    ├── static/
    │   ├── css/
    │   └── img/
    ├── template.html
    ├── index.md
    └── about.html
  • src/: The root for all source content.
  • src/template.html: The master template required for all pages.
  • src/includes/: A reserved directory for HTML snippets that can be included in other files.
  • src/static/: All contents of this directory are copied directly to dist/static/.
  • dist/: The output directory where the generated site is placed. This is created automatically.

Templating System

fssg uses a simple but powerful text-based templating system.

Global Template

The file src/template.html is the master layout. It must contain {{content}}, which acts as the placeholder for each page's processed content. It can also contain {{title}}.

Title Variable

The page title is determined with the following priority:

  1. An explicit {{title: My Page Title}} tag anywhere in the page's content file.
  2. If not found, the title is generated from the filename (e.g., my-first-post.md becomes "My First Post").

Simple Includes

To embed a file from src/includes/, use the include directive.

{{include: footer.html}}

Block Includes with Parameters

For more complex components, you can pass parameters and a block of content to an include. The content you provide is injected wherever {{content}} appears inside the include file.

Example src/includes/alert.html:

<div class="alert alert-{{type}}">
  <strong>{{alert_title}}:</strong>
  {{content}}
</div>

Usage in a page:

{{include-block: alert.html type="warning" alert_title="Attention"}}
  <p>This is an important message.</p>
{{endinclude}}

Content Processing

Markdown Parser

fssg uses a capable awk-based Markdown parser with support for a wide range of features:

  • Headings (# H1 to ###### H6)
  • Paragraphs (automatic <p> wrapping)
  • Raw HTML passthrough (lines that start with <...>)
  • Blockquotes (> quote)
  • Unordered Lists (*, -, +) and Ordered Lists (1., 2., ...)
  • Fenced Code Blocks (```lang ... ```) and Inline Code (`code`)
  • Links ([text](url))
  • Images (![alt text](src))
  • Emphasis: Bold (**text**), Italic (*text*), Strikethrough (~~text~~)
  • Horizontal Rules (---, ***, ___)
  • Tables (GitHub-style with pipes: | a | b |)

Asset Pipeline

All files and directories inside src/static/ are copied recursively to dist/static/.

Style & Script Hoisting

A powerful optimization feature: all <style>...</style> and <script>...</script> blocks from your page content are automatically extracted, deduplicated, and moved. Styles are placed just before the closing </head> tag, and scripts are placed just before the closing </body> tag. This improves rendering performance and helps organize page-specific code.

Conditional Logic

You can render content conditionally based on the page being built. This is useful in shared templates or includes.

By Output Page Path

Render content only if the output file path matches. The path is relative to the dist/ directory (e.g., index.html, blog/my-post.html).

{{IF_PAGE: index.html}}
  <p>Only for the homepage.</p>
{{ELIF_PAGE: about.html}}
  <p>Only for the about page.</p>
{{ELSE_PAGE}}
  <p>For all other pages.</p>
{{ENDIF_PAGE}}

By Source File Extension

Render content based on the source file’s extension (md, html, or any other).

{{IF_EXT: md}}
  <p>This content was originally a Markdown file.</p>
{{ELIF_EXT: html}}
  <p>This content was originally an HTML file.</p>
{{ELSE_EXT}}
  <p>This content came from another source format.</p>
{{ENDIF_EXT}}

Automated Post Listings

fssg can automatically generate lists of posts. To be recognized as a post, a file must be named with a date prefix like YYYY-MM-DD-your-post-slug.md.

Recent Posts

Displays a simple list of the most recent posts.

{{recent-posts count="3" show_images="true"}}

All Posts (with Pagination)

Generates a list of all posts, typically for an archive page, with optional pagination.

{{all-posts page_size="5" pagination="true"}}

Available Parameters

  • count / page_size: Number of posts to show.
  • page: The current page number for pagination.
  • pagination: Set to "true" to show pagination links.
  • show_images: Set to "true" to include post images.
  • ul_class, li_class, time_class, link_class, img_class: Customize the CSS classes of the generated HTML elements.

Post Image Logic

When show_images="true", fssg finds an image using this priority:

  1. The src of the first <img> tag found in the post's content.
  2. If no image is in the content, it looks for a fallback image at src/static/posts/<slug>.jpg (or .png, .gif, etc.).