Skip to main content

neostatic

A small static site generator for blogs, written in Python.

TOML config → Markdown posts (Markdown-metadata frontmatter) → Jinja2 templates → static output directory → upload.

Kind of a love-letter to neocities.org.

Why this exists

Most static site generators (Hugo, Zola, Jekyll) are general-purpose templating systems that happen to be good at blogs. neostatic does the opposite: it only does one shape of site (a blog, plus static passthrough content), and stays small enough to read end to end in one sitting.

A few things that follow from that:

  • Upload is part of the tool, not bolted on afterward. neostatic renders to a local site/ directory and then pushes it straight to Neocities in the same invocation (--offline skips the upload step). Most generators render only and leave publishing to a separate script.
  • It refuses to destroy a source tree. If the output directory itself contains .git or the site's own neostatic.toml, neostatic treats that as a sign it's pointed at the wrong place and stops rather than deleting it.
  • TOML for config, Markdown metadata for posts. Site config is TOML; post frontmatter uses Python-Markdown's meta extension rather than a second data format embedded in the post.

Quick start

python -m neostatic <site-dir> [-v] [--offline] [--dry-run]

A site directory looks like:

site-dir/
  neostatic.toml
  static/            # copied through as-is (allow-listed extensions)
  templates/
    index.html
    blogpost.html    # default post template; override per-post
  posts/
    2024-01-01-hello.md

Config (neostatic.toml)

[blog]
 [blog.paths]
  static = "static"
  templates = "templates"
  posts = "posts"
  site = "site"
 [blog.meta]
  title = "example"
  strapline = "a blog"

[neocities]
 proxy = "socks5://127.0.0.1:9150"   # optional, e.g. for publishing over Tor
 user = "..."
 password = "path/to/password-file"  # contents read at load time, not inline
 api_key = "path/to/api-key-file"    # preferred over user/password if present

[blog.paths] and [neocities] are both optional; paths default to the names shown above, and Neocities upload just isn't available without that section. If api_key isn't set yet but a path is given, neostatic will fetch a key on first run (using user/password) and write it there.

Posts

Markdown-extension frontmatter, no delimiters — a block of key: value lines followed by a blank line:

title: Hello
date: 2024-01-01T12:00:00+00:00
published: true
summary: An optional one-line summary.
slug: hello
template: blogpost

Body in Markdown.

Only title and date are required. published defaults to false; slug defaults to a slugified title; template defaults to blogpost. Only published: true posts get a generated page and appear in the index; everything else is loaded but skipped at render time.

Release files for neostatic 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for neostatic 0.1.0
File Size Uploaded
neostatic-0.1.0.tar.gz 24.5 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for neostatic 0.1.0
File Interpreter ABI Platform
neostatic-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 48.4 kB

Release files / neostatic-0.1.0.tar.gz

Download URL neostatic-0.1.0.tar.gz
Size 24.5 kB
Tags Source
SHA-256 checksum
How to use checksums
6ab2b9601ddaeddda3954319a72209f43cb9879969c7237c5244a938867c28d1
BLAKE2b-256 checksum
How to use checksums
e8cb7bbded656fa2edc67faab48a9273128fd7601d073c483a1ab9888bc3e13d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.7

Release files / neostatic-0.1.0-py3-none-any.whl

Download URL neostatic-0.1.0-py3-none-any.whl
Size 23.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
6723602d9f2d4cf1d4c336450602b33c141c84f3ff862a2f363fab955d617d86
BLAKE2b-256 checksum
How to use checksums
5478b1c588b81493422fb2da37fedc54247c584cb76f437d43e9c09338a8a165
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.7

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page