Skip to content

Starlette-Templates

Documentation | PyPI

Starlette-Templates serves a folder of pages as a Starlette app. You give it a Jinja2 loader. It serves assets unchanged, renders templates on each request, and turns Markdown into HTML.

The package has a small set of parts:

  • Static files — an ASGI app that serves the directories behind a Jinja2 loader.
  • Named SQL queries — a page declares a query and runs it through a query runner you supply.
  • Shortcodes — each template file in a folder becomes a Jinja tag.
  • HTMX fragments — each template in fragments/ re-renders itself when a trigger fires.
  • HTML in Python — build elements and documents with ht, Element, and Document.
  • Error handling — raise AppException to get an HTML page or a JSON:API document.

Each part is a folder convention, not a registry. You add a page, a shortcode, or a fragment by adding a file.

Why use Starlette-Templates

Starlette gives you the ASGI building blocks. Serving a folder of pages still takes a lot of glue. This package is that glue. The main features:

  • One loader — a FileSystemLoader, a PackageLoader, or a ChoiceLoader chain. A ChoiceLoader lets an application file override a framework file.
  • Templates and Markdown — a .jinja file renders on each request. The include_markdown() helper pulls in a Markdown file, and a {% markdown %} block holds Markdown written in the template. Both accept Jinja.
  • Template globals — every template gets request, url_for, jsonify, and include_markdown. You can add your own globals and filters.
  • HTTP caching — ETag and Last-Modified headers, 304 Not Modified responses, and Cache-Control you set.
  • SQL in the page — a page declares a named query. Nothing runs until the page calls fetch(). The query string supplies the placeholders, bound out of band.
  • One response, several updates — an htmx handler says what happened. Every stale fragment renders and rides back in the same response.
  • Strict at start — a bad name or a collision raises ValueError when you build the app, not on a request.

Installation

pip install starlette-templates

Hello world example

from jinja2 import FileSystemLoader
from starlette.applications import Starlette
from starlette.routing import Mount

from starlette_templates import StaticFiles

app = Starlette(
    routes=[
        Mount("/", StaticFiles(loader=FileSystemLoader("site"), html=True), name="site"),
    ]
)

Create site/index.html.jinja:

<!DOCTYPE html>
<html>
<head><title>My App</title></head>
<body><h1>Welcome to {{ request.url.hostname }}</h1></body>
</html>

Run the app:

uvicorn app:app --reload

Open http://localhost:8000/ and StaticFiles renders the template. It serves the plain files in the same directory — CSS, JavaScript, images — unchanged, with caching headers.

Choose your path

If you want to Read this
Serve assets, templates, and Markdown Static files
Run a query from a page Named SQL queries
Turn a folder of snippets into Jinja tags Shortcodes
Update several parts of a page from one response HTMX fragments
Build HTML without a template file HTML in Python
Return an error as a page or as JSON Error handling
Look up a class or a function API reference

LLM context

This documentation is available as an LLM-friendly Markdown file: