The monolithic Norg static site generator built with Rust. Leverage rust-norg syntax validation with Norg-to-HTML conversion to build static sites from Norg content.
- Norg-native content with validation via rust-norg
- Tera v2 templates with shortcodes, optional chaining, and rich filters
- C ABI plugin system with Landlock sandboxing (filesystem confinement, timeout, panic isolation)
- Incremental builds via content-hash caching
- Parallel builds powered by Rayon
- SEO out of the box: sitemap.xml, robots.txt, OpenGraph, Twitter Cards
- Custom error pages (404.html, 500.html)
- Live preview dev server with hot reload and config hot-reloading
- Plugin sources: install from crates.io, Git repositories, or local paths
βοΈ Comparison with Hugo and Zola
| Dimension | Hugo | Zola | Norgolith |
|---|---|---|---|
| Language | Go | Rust | Rust |
| Templates | Go templates | Tera v1 | Tera v2 + shortcodes |
| Content format | Markdown + 5 others | Markdown only | Norg only |
| Plugin system | None | None | C ABI + Landlock sandbox |
| Content validation | None | Link checking | rust-norg parser + schemas |
| Syntax highlighting | Built-in (Chroma) | Built-in | Via plugin (tree-sitter) |
| Image processing | Yes | Yes | Planned |
| Asset bundling | Yes | No | Planned |
| Asset fingerprinting | Yes | No | Planned |
| Configuration | TOML / YAML / JSON | TOML | TOML |
| Multilingual | Yes | Yes | No |
| Shortcodes | Built-in | No | Tera v2 component() |
| Custom output | JSON, RSS, etc | RSS, Atom | RSS, Atom |
| Theme system | Yes | Yes | Yes |
| Built-in search | No | Yes | Via plugin |
| Build | Parallel (pages) | Parallel | Parallel + incremental |
| Component | Requirement |
|---|---|
| Build | Rust >= 1.85 (Rust 2024 edition) |
Run cargo install --release --path . to compile and install Norgolith in your ~/.cargo/bin directory.
π¨ AUR
Use Arch User Repository helper to install norgolith-git.
paru -S norgolith-git
π¦ Nix Package
For latest release version: nix-shell -p norgolith.
For git version you can add Norgolith to NixOS configuration with flakes.
{
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
norgolith.url = "github:norgolith/core";
};
outputs =
{ nixpkgs, norgolith, ... }:
{
nixosConfigurations.mysystem = nixpkgs.lib.nixosSystem {
modules = [
{
environment.systemPackages = [
norgolith.packages.x86_64-linux.default
];
}
];
};
};
}π¦ Plugin SDK
Install from crates.io into your plugin project:
cargo add norgolith-plugin-sdkOr build from the flake:
nix build .#norgolith-plugin-sdkAdd it to your NixOS configuration:
environment.systemPackages = [
norgolith.packages.x86_64-linux.norgolith-plugin-sdk
];Scaffold a new plugin with lith plugin new my-plugin, which generates plugin.toml, Cargo.toml, and src/lib.rs.
Hooks: pre_build, post_convert, post_render, post_build.
Sandboxing: Landlock filesystem confinement, configurable timeout per hook, panic isolation.
Logging: plugin_log! macro bridges to Norgolith's tracing pipeline.
The canonical plugin is written in Rust using the SDK:
use norgolith_plugin_sdk::*;
register_plugin!("my-plugin",
hooks: [post_render: my_hook]
);
fn my_hook(json: serde_json::Value) -> Result<Option<String>, String> {
let ctx: TransformContext = serde_json::from_value(json)
.map_err(|e| e.to_string())?;
Ok(Some(ctx.html))
}Plugins use Norgolith's C ABI, so any language that exports C functions can participate. A C plugin looks like:
#include <stdint.h>
#include <string.h>
#define HOOK_POST_RENDER 4
typedef char* (*plugin_fn)(const char*);
typedef struct {
uint32_t abi_version;
const char* name;
const char* version;
void (*log_fn)(uint32_t, const char*);
} plugin_info;
char* post_render(const char* input) {
/* parse input JSON, return modified HTML or NULL */
return NULL;
}
void norgolith_plugin_init(plugin_info* info, uint32_t* mask, plugin_fn hooks[4]) {
info->abi_version = 1;
info->name = "my-c-plugin";
info->version = "0.1.0";
*mask = HOOK_POST_RENDER;
hooks[2] = post_render;
}For Lua, write a small C shim that embeds Lua and dispatches hook calls to a .lua script:
// c-shim.c β compiles to a .so that Norgolith loads
#include <lua5.4/lua.h>
#include <lua5.4/lauxlib.h>
static lua_State *L;
void norgolith_plugin_init(plugin_info* info, uint32_t* mask, plugin_fn hooks[4]) {
L = luaL_newstate();
luaL_dofile(L, "my-plugin.lua");
*mask = HOOK_POST_RENDER;
hooks[2] = &bridge;
}
char* bridge(const char* input) {
/* push input, call my-plugin.lua's post_render, return result */
}See sdk/README.md and norgolith.dev/docs/plugins for full documentation.
π€ MCP Server
Install from crates.io:
cargo install norgolith-mcpOr build from source:
cargo build --release --manifest-path norgolith-mcp/Cargo.tomlOr build from the flake:
nix build .#norgolith-mcpAdd it to your NixOS configuration:
environment.systemPackages = [
norgolith.packages.x86_64-linux.norgolith-mcp
];Configure in your MCP client:
{
"mcp": {
"norgolith": {
"type": "local",
"command": "norgolith-mcp",
"enable": true
}
}
}Capabilities: resources (norgolith://docs/*), tools (search_docs, read_source).
See norgolith-mcp/README.md for details.
lith init my-site
cd my-site
lith new -k post hello-world
lith dev --open
lith buildThe produced binary is called lith for short.
$ lith --help
The monolithic Norg static site generator
Usage: lith [OPTIONS] <COMMAND>
Commands:
init Initialize a new Norgolith site
theme Theme management
dev Run a site in development mode
new Create a new asset in the site and optionally open it using your preferred system editor. e.g. 'new -k norg post1.norg' -> 'content/post1.norg'
build Build a site for production
plugin Plugin management
preview Preview from build result
help Print this message or the help of the given subcommand(s)
Options:
-v, --version Print version
-d, --dir <PROJECT_DIR> Operate on the project in the given directory
-h, --help Print help
π Plugin Development
Norgolith ships a C ABI plugin system. Plugins are shared libraries (.so, .dylib, .dll) loaded at runtime and sandboxed with Landlock.
Hook pipeline:
Content --> pre_build --> post_convert --> Tera render --> post_render --> post_write --> post_build
Plugin install:
lith plugin install ./my-plugin # from local path
lith plugin install norgolith-tree-sitter # from crates.io
lith plugin install --git https://github.com/norgolith/norgolith-tree-sitter.gitSandboxing: each plugin gets filesystem confinement (configurable: none / read / write / read-write), a per-hook timeout (default 10s), and panic isolation.
See sdk/README.md for the full plugin guide.
βοΈ Developing with Nix
The repository includes a Nix flake for development and testing.
nix build . # build, output in result/
nix run . # build and run
nix develop . # dev shell with all dependenciesFor Nix-direnv integration, entering the directory activates the dev shell automatically.
The documentation site source lives in the docs/ directory. To work on it:
# From repo root, enter dev shell (includes tailwindcss, mprocs).
nix develop
# Build lith
cargo build --release
# Start docs dev server
cd docs
mprocsSee docs/README.md for details.
Join the Neorg community and get help or discuss about the project:
Developing and maintaining open-source projects takes time and effort. If you find Norgolith valuable and would like to support its continued development, here are some ways you can help:
- Star this repository on GitHub: this helps raise awareness and shows the project is actively maintained.
- Contribute code or documentation: we welcome contributions from the community.
- Spread the word: let others know about Norgolith if you think they might benefit from it.
- Financial Support (Optional): if you'd like to offer financial support, you can consider using my Ko-fi page (linked in the repository). Any amount is greatly appreciated and helps me invest further time in Norgolith's development.
Huge thanks to the project sponsors for supporting my work!
This project is licensed under the GNU General Public License v2 (GPLv2). You can find the license details in the LICENSE file.

