StaPy is a Static Site Generator made with Python
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
magentix bfaddacdc2 Garden theme added 1 week ago
source Copyright removed 2 weeks ago
tests Fix missing web dir local renderer 2 weeks ago
tools Reserved Requests API improvements 1 month ago
web/prod Useless file deleted 8 months ago
LICENCE Copyright updated 9 months ago Garden theme added 1 week ago Query sort order with integer 1 week ago


StaPy is a Static Site Generator. It works with Python without any additional package.


Requires Python 3.4 or newer on any operating system.


Create a project directory anywhere and download the last release from the StaPy repository.

mkdir stapy
cd stapy
tar zxvf last.tar.gz --strip 1
rm last.tar.gz

HTTP server

Run standalone HTTP server:


On Windows 10 just double-click on the file.

Then access the URL http://localhost:1985


Static files are generated in the web directory. This directory contains all the necessary environment directories (devel, prod...).

For the production, add a prod directory in the web directory. It will contain all pages and files you need to deploy (html, css, js, images...).

After you add a new environment, you must restart the server.


When a page is open in the browser, the server search a json file in source/json directory. The name of the json file is the same as the URL path. Examples:

URL Path Json file
/ index.html.json
/hello.html hello.html.json
/hello/world.html hello/world.html.json
/hello/world/ hello/world/index.html.json

If the json file does not exist, a 404 error is sent.


The json file contains all the data required for generate the page:

  "title": "Page title",
  "description": "Page description",
  "template": "template/default.html",
  "content": "page/index.html"

The template key is required.

Set the environment variables with the environment suffix:

  "url.local": "http://localhost:1985/",
  "": ""

The environment suffix must have the same name as your environment directory. For local rendering, the suffix is always "local".

A variable can have a default value:

  "my_text": "All environments display this text",
  "my_text.local": "Except the local with this"

A file named html.json in the source/json/default directory is used for the default html page configuration. It will be merged with the page's json file. This is useful for a global configuration.


  "title": "Default title",
  "template": "template/default.html"


  "title": "Home title",
  "content": "page/index.html"

default/html.json + index.html.json

  "title": "Home title",
  "template": "template/default.html",
  "content": "page/index.html"

You can add default config file for any file extensions you need:

  • default/xml.json
  • default/txt.json
  • ...

The default/common.json config file is available for all pages (all extensions).

Note: the default config file is optional.

Tip: Add _page/ before the path to fetch json data.



The template file is the skeleton of the page:

<!DOCTYPE html>
<html lang="fr">
        <meta charset="utf-8">
        <title>{{ meta_title }}</title>
        <meta name="description" content="{{ meta_description }}" />
        <link rel="stylesheet" href="{{ url }}css/style.css" />
            {% header %}
            {% content %}
            {% footer %}


  • All variables in double curly braces {{ }} will be replaced with the text declared in the json file for the var.
  • All variables in curly brace percent {% %} will be replaced with the content of the file declared in the json file for the var.

Tip: set empty string for a content file variable in the json file to replace it with empty text.

Child block

Use specific json data for the child content with a + separator (spaces are required):

{% post + my-first-post.html %}

The json/my-first-post.html.json data will be accessible in the post template, with a $ before the var:

<a href="{{ url }}{{ $_path }}">{{ $post_title }}</a>

To loop json data with a query, use ~ as separator (spaces are required):

{% post ~ {key:value} {key:dir} {start:end} %}
  • key:value - Search value in the data of the specified key
  • key:dir - Sort by key, asc or desc
  • start:end - Retrieve data from start to end


{% post ~ tags:post date:desc 1:10 %}

This query retrieves the 10 first pages with post value in tags, sorted by date. The tags and date vars must be present in the json data of the pages:

  "date": "2022-01-01",
  "tags": ["post"]

The json data will be accessible in the post template, with a $ before the var.

Reserved variable

In any template, the _path var is reserved for the current page path:

{{ url }}{{ _path }}
<!-- -->


All necessary resources like js, css or images are copied from the source/assets directory in all environment directories (e.g. web/prod).

Static files

The final static HTML files and resources are added or refreshed when the pages are opened in the browser. When /hello.html is open, the hello.html file is automatically generated in all environment directories (e.g. web/prod).


The website can be regenerated with a crawler. StaPy gives a python crawler script in the tools directory.

python3 tools/ {delete} {copy} {crawl}
  • delete: remove content from all environments
  • copy: copy the source/assets directory to all the environment directories
  • crawl: generate all the pages declared in the json files

Launch crawler with no option perform delete, copy and crawl:

python3 tools/

PUT 200
HEAD 200 /index.html
HEAD 200 /hello.html


If you are using an automated deployment tool like Netlify, Cloudflare Pages, Vercel or Render, configure the tool to deploy the environment directory from the git repository (e.g. web/prod).

To deploy with Github Pages, create a docs directory with a symlink from web/prod to docs. Commit and push the docs directory, then configure Github Pages to deploy docs.


Simple and minimal themes for StaPy: