A small static site generator built on Python and Jinja.
Documentation
The full documentation lives in docs/ and is built with Zensical.
Preview it locally with zensical serve; it is published at
https://jamstackpy.github.io/.
Jamstack turns a folder of Markdown and Jinja templates into a static site.
There is no database, no runtime, and no network access during a build: you
write content, run one command, and deploy the generated dist/ folder
anywhere.
Features
- Markdown pages with TOML front matter, or raw Jinja templates when you need full control.
- Themes as plain folders: bundled ones, your own, or a per-project override.
- A development server that rebuilds on change and keeps the last good build when something fails.
sitemap.xml, an Atom feed, and a themed404.htmlgenerated for you.- Deterministic output: the same sources always produce the same bytes.
- Three runtime dependencies:
click,jinja2,markdown-it-py.
Installation
python -m pip install jamstack
Python 3.11 or newer is required.
Quick start
jamstack init my-site --theme blog
cd my-site
jamstack build
jamstack serve
jamstack init scaffolds site.toml, a starter page, and the files the chosen
theme needs. jamstack build writes the site to dist/. jamstack serve
serves it at http://127.0.0.1:8000 and rebuilds when a source changes.
Project layout
my-site/
site.toml # site configuration
content/ # pages (.md or .html)
static/ # files copied as-is to the output root
templates/ # optional overrides of the theme's templates
themes/ # optional local themes
dist/ # build output (do not edit)
Writing content
A page is a file under content/. Its path becomes its URL:
| Source | URL | Output |
|---|---|---|
content/index.md |
/ |
dist/index.html |
content/about.md |
/about/ |
dist/about/index.html |
content/posts/hello.md |
/posts/hello/ |
dist/posts/hello/index.html |
Markdown files may start with TOML front matter delimited by +++:
+++
title = "Hello, world"
date = 2026-11-06
summary = "The first post."
+++
This is **Markdown**.
Recognised keys:
| Key | Type | Meaning |
|---|---|---|
title |
string | Page title. Defaults to the file name. |
date |
ISO date | Publication date. Feeds and listings order by it. |
template |
string | Template to render the page with. |
draft |
boolean | Excluded from builds unless --drafts is passed. |
summary |
string | Short description used by feeds and the blog theme. |
Any other key is available to templates as page.meta. Files ending in
.html are rendered as Jinja templates instead of Markdown, which makes it
easy to build landing pages with custom markup.
Configuration
[site]
title = "My Site" # required
description = ""
author = ""
base_url = "https://example.com" # required for sitemap.xml and feed.xml
language = "en"
[build]
output = "dist"
[theme]
name = "blog"
base_url must be the public, absolute URL of the site. When it is set,
Jamstack writes sitemap.xml with every page and feed.xml with every dated
page. When it is empty, both files are skipped rather than emitting relative
URLs.
Themes
List the available themes with:
jamstack themes
Two themes ship with the package: minimal for small sites and blog for
dated posts. A project can override a bundled theme by creating
themes/<name>/ inside the project; local themes take precedence.
Themes are plain folders, so a custom theme is just a directory with a
theme.toml, templates/, and optionally static/ and scaffold/. See
docs/themes.md for the full specification.
Command reference
| Command | Description |
|---|---|
jamstack init [PATH] [--theme NAME] [--force] |
Create a new site. |
jamstack build [--clean] [--drafts] |
Build the site into dist/. |
jamstack serve [--port PORT] [--drafts] |
Build, serve, and rebuild on change. |
jamstack themes |
List available themes. |
jamstack --version |
Print the installed version. |
python -m jamstack behaves like the jamstack command.
Migrating from 1.x
The 1.x engine (settings.py, posts.json, static.py, html5up themes) is
replaced entirely in 2.0. See docs/migration.md for a
step-by-step conversion guide, or keep using 1.x with:
python -m pip install "jamstack<2"
Development
git clone git@github.com:jamstackpy/jamstack.git
cd jamstack
git switch stable
python -m venv .venv
. .venv/bin/activate
pip install -e ".[dev]"
pre-commit install --hook-type pre-commit --hook-type commit-msg
pytest
Commits follow Conventional Commits; see CONTRIBUTING.md.
License
Apache-2.0. The 1.x html5up templates were distributed under CC BY 3.0 and are no longer part of this branch.
Metadata
Release files for jamstack 2.1.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| jamstack-2.1.1.tar.gz | 159.2 kB | With provenance | Details for jamstack-2.1.1.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| jamstack-2.1.1-py3-none-any.whl | Python 3 | none | any | Details for jamstack-2.1.1-py3-none-any.whl |
Total release size: 184.2 kB
Release files / jamstack-2.1.1.tar.gz
| Download URL | jamstack-2.1.1.tar.gz |
|---|---|
| Size | 159.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
df3f5ea26bcc3b11179fd541b0e33a1396e1c051a89e3c5cb2549e85386de658
|
|
BLAKE2b-256 checksum How to use checksums |
f0884a98839316a89795583d224ad514d0e55e20758496fd7c08441c6059ab61
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 7, 2026.
Transparency logRelease files / jamstack-2.1.1-py3-none-any.whl
| Download URL | jamstack-2.1.1-py3-none-any.whl |
|---|---|
| Size | 25.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
a1cd674b12a33e1a9be37d4df18618c650dae944db3ed3ee9b6ee606a5a13142
|
|
BLAKE2b-256 checksum How to use checksums |
e1a82f6858c2c4d6f310f04012491f3594bedefe31bb838b3ad54241f8db59e8
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 7, 2026.
Transparency logSecurity for jamstack 2.1.1
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
Both files in this release have been uploaded with provenance metadata.
Attestation for jamstack-2.1.1.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 7, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.