Modular Python web framework with hot-mount dynamic modules — FastAPI + SQLAlchemy + Jinja + HTMX + Alpine.
Project description
Modular Python web framework with hot-mount dynamic modules.
What is hotframe
hotframe is a Python web framework that unifies FastAPI, SQLAlchemy 2.0, Jinja2, HTMX, and Alpine.js under Django-like ergonomics. It adds a hot-mount module engine — load and unload plugins at runtime without restarting the process — and a Turbo/Livewire-style HTMX layer for server-driven UI. Built for teams who want the productivity of Rails or Django with the async performance of FastAPI.
Quickstart
pip install hotframe
hf startproject myapp
cd myapp
hf runserver
INFO hotframe.core - Loading kernel modules...
INFO hotframe.modules - Mounted: core, auth, admin (3 modules)
INFO hotframe.server - Uvicorn running on http://127.0.0.1:8000
INFO hotframe.server - Press CTRL+C to quit
The CLI installs two aliases: hf (short) and hotframe (explicit).
Key Features
-
Hot-mount dynamic modules — Load and unload Python modules at runtime via a DB registry with topological dependency resolution. No process restart required.
-
HTMX layer (Turbo/Livewire-style) —
@htmx_viewdecorator, named frames, TurboStream responses, out-of-band swaps, and server-sent event broadcasting. Build rich UIs without writing JavaScript. -
Django-like ergonomics —
AppConfig,settings.py, management commands, scaffolding CLI. Familiar conventions so teams onboard in minutes, not days. -
AsyncEventBus + HookRegistry — WordPress-style actions and filters across modules. Decouple features without tight imports. Fully async-native.
-
SQLAlchemy 2.0 + Alembic — Async sessions, per-module migration namespaces, and automatic migration discovery. No shared migration root.
-
Jinja2 + Alpine.js integration — Template inheritance, context processors, CSP-safe nonce injection, and Alpine.js wired out of the box.
-
OpenTelemetry observability — Traces, metrics, and structured logs built into the request lifecycle. Zero extra setup for OTLP exporters.
-
CLI scaffolding —
hf startproject,hf startapp,hf startmodule,hf makemigrations,hf migrate. Generate production-ready skeletons from the command line.
Comparison
| Feature | Rails Turbo | Laravel Livewire | Phoenix LiveView | Django + htmx | hotframe |
|---|---|---|---|---|---|
| Language | Ruby | PHP | Elixir | Python | Python |
| Server-driven UI | Yes | Yes | Yes | Partial | Yes |
| Hot-reload modules | No | No | No | No | Yes |
| Async-native | No | No | Yes | No | Yes |
| ORM | ActiveRecord | Eloquent | Ecto | Django ORM | SQLAlchemy 2.0 |
| Per-module migrations | No | No | No | No | Yes |
| Plugin hooks system | No | No | No | No | Yes |
| CLI scaffolding | Yes | Yes | Yes | Yes | Yes |
| PyPI installable | No | No | No | Yes | Yes |
Minimal Example
Define a module with a model, a route, and a template in under 20 lines:
# modules/blog/module.py
from hotframe.modules import ModuleConfig
class BlogModule(ModuleConfig):
name = "blog"
version = "1.0.0"
dependencies = ["core", "auth"]
# modules/blog/models.py
from hotframe.db import Base
from sqlalchemy.orm import Mapped, mapped_column
class Post(Base):
__tablename__ = "blog_posts"
id: Mapped[int] = mapped_column(primary_key=True)
title: Mapped[str]
body: Mapped[str]
# modules/blog/views.py
from hotframe.htmx import htmx_view
from hotframe.routing import router
from .models import Post
@router.get("/blog")
@htmx_view(template="blog/index.html")
async def post_list(request):
posts = await Post.all()
return {"posts": posts}
<!-- modules/blog/templates/blog/index.html -->
<div hx-get="/blog" hx-trigger="every 30s" hx-swap="innerHTML">
{% for post in posts %}
<article>{{ post.title }}</article>
{% endfor %}
</div>
Mount it:
# settings.py
INSTALLED_MODULES = ["core", "auth", "blog"]
Architecture Overview
hotframe is organized in three layers:
Runtime layer — the framework kernel. Boots FastAPI, wires middleware, initializes the DB engine, and exposes the public API (@htmx_view, router, settings, EventBus, HookRegistry).
Module layer — each module is a Python package with a ModuleConfig subclass, its own models, views, templates, migrations, and static assets. The module engine resolves dependency order, mounts routes and Alembic migration contexts, and registers hook namespaces. Modules can be installed, uninstalled, enabled, and disabled at runtime via the admin API without touching the running process.
HTMX layer — sits on top of FastAPI responses. The @htmx_view decorator detects HX-Request headers and returns partial renders or full-page responses automatically. TurboStream helpers produce text/vnd.turbo-stream.html responses for out-of-band DOM updates. The EventBus integrates with server-sent events for real-time broadcasting to named HTMX frames.
The CLI (hf) is a Typer application that wraps Uvicorn, Alembic, and the scaffolding generators. It reads settings.py from the project root and discovers modules from INSTALLED_MODULES.
Documentation
Documentation is available in the docs/ directory.
License
Apache 2.0. Copyright 2026 ERPlora.
Contributing
See CONTRIBUTING.md. Feedback and issue reports are welcome while the project is in pre-alpha. Code contributions open on first stable release.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file hotframe-0.0.1.tar.gz.
File metadata
- Download URL: hotframe-0.0.1.tar.gz
- Upload date:
- Size: 1.6 MB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ebc70d16ae49e64d3aa19e2d6e87d512bce537a3b0de4dc498802f059b7b11e1
|
|
| MD5 |
737e96a9ea31a158429625f140ce63f6
|
|
| BLAKE2b-256 |
71ad6e396a3ea715cd1caa646bc1d032b2cde26665fecfcf0244f7454f3aa771
|
Provenance
The following attestation bundles were made for hotframe-0.0.1.tar.gz:
Publisher:
publish.yml on ERPlora/hotframe
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
hotframe-0.0.1.tar.gz -
Subject digest:
ebc70d16ae49e64d3aa19e2d6e87d512bce537a3b0de4dc498802f059b7b11e1 - Sigstore transparency entry: 1339539410
- Sigstore integration time:
-
Permalink:
ERPlora/hotframe@ec6f572806f5ac888424e2a66b36e058d57616e7 -
Branch / Tag:
refs/tags/v0.0.1 - Owner: https://github.com/ERPlora
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@ec6f572806f5ac888424e2a66b36e058d57616e7 -
Trigger Event:
release
-
Statement type:
File details
Details for the file hotframe-0.0.1-py3-none-any.whl.
File metadata
- Download URL: hotframe-0.0.1-py3-none-any.whl
- Upload date:
- Size: 197.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a71d9611564a0388ee4ce3e235bd2b083bb4719cb0bc1cd6172535cfd47d435f
|
|
| MD5 |
2d84993325172fdc6737d41c519fe3b3
|
|
| BLAKE2b-256 |
7eab6ff892aaaa05e002f3682bb1560bcb7a9aa125cc3e6abe003bbda298737a
|
Provenance
The following attestation bundles were made for hotframe-0.0.1-py3-none-any.whl:
Publisher:
publish.yml on ERPlora/hotframe
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
hotframe-0.0.1-py3-none-any.whl -
Subject digest:
a71d9611564a0388ee4ce3e235bd2b083bb4719cb0bc1cd6172535cfd47d435f - Sigstore transparency entry: 1339539414
- Sigstore integration time:
-
Permalink:
ERPlora/hotframe@ec6f572806f5ac888424e2a66b36e058d57616e7 -
Branch / Tag:
refs/tags/v0.0.1 - Owner: https://github.com/ERPlora
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@ec6f572806f5ac888424e2a66b36e058d57616e7 -
Trigger Event:
release
-
Statement type: