starlette-hot-reload
Hot reload for Starlette templates and static files
Overview
starlette-hot-reload reloads the browser when your Starlette templates or
static assets change. It injects a small client script into HTML responses and
uses Server-Sent Events (SSE) to notify the browser about changes.
Quick Start
Install the package:
uv add starlette-hot-reload
# or
pip install starlette-hot-reload
Enable it in your app lifespan:
from contextlib import asynccontextmanager
from starlette.applications import Starlette
from starlette_hot_reload import hot_reload
@asynccontextmanager
async def lifespan(app: Starlette):
async with hot_reload(app=app, watch_dirs=["templates", "static"]):
yield
app = Starlette(
debug=True,
lifespan=lifespan,
)
Run your app:
uvicorn main:app
What You Get
- Reloads the browser when watched files change.
- Injects the client script into HTML responses automatically.
- Uses SSE, no websocket.
- Composes with Starlette lifespan context managers.
- Adds no extra runtime dependency beyond Starlette.
Basic Usage
Hot reload only runs when debug=True.
app = Starlette(debug=True)
Watch specific directories:
@asynccontextmanager
async def lifespan(app: Starlette):
async with hot_reload(
app=app,
watch_dirs=["templates", "static", "assets"],
):
yield
Use a custom SSE endpoint:
async with hot_reload(
app=app,
watch_dirs=["templates", "static"],
events_path="/custom-events-path",
):
...
Tune filesystem polling:
async with hot_reload(
app=app,
watch_dirs=["templates", "static"],
poll_interval=0.25,
):
...
Compose it with other lifespan resources using AsyncExitStack:
from contextlib import AsyncExitStack, asynccontextmanager
@asynccontextmanager
async def lifespan(app: Starlette):
async with AsyncExitStack() as stack:
await stack.enter_async_context(
hot_reload(app=app, watch_dirs=["templates", "static"])
)
yield
How It Works
When you request an HTML page, the middleware injects a small client script into the response body. That script opens an SSE connection to the app.
The file watcher polls the directories you configured. When a file changes:
- Watched changes trigger a full page reload.
This package complements server reload tools such as uvicorn --reload. It does
not restart your Python process.
Limits
- Hot reload is disabled when
debug=False. - The watcher uses polling, not native OS file notifications.
- Python code changes reload the browser page, but they do not reload server state or restart the app process.
- Script injection targets HTML responses. Non-HTML responses are left alone.
Examples
The repository includes example apps under examples/.
examples/basic
This example shows the smallest Starlette setup with:
- Jinja templates
- Static files
hot_reload()in the app lifespan
Run it from the repository root:
uv run python -m examples.basic.app
Open http://127.0.0.1:3000 and edit files in examples/basic/templates or
examples/basic/static.
examples/with_tailwind
This example shows how to compose starlette-hot-reload with
starlette-tailwindcss.
It watches the whole example directory so changes to templates, CSS, and built assets all trigger a browser reload.
Run it from the repository root:
uv run python -m examples.with_tailwind.app
Open http://127.0.0.1:3000 and edit files in examples/with_tailwind/.
Debug Logging
If you want watcher and SSE logs during development, enable Python logging:
import logging
import sys
logging.basicConfig(
level=logging.DEBUG,
format="%(asctime)s %(levelname)s [%(name)s] %(message)s",
datefmt="%Y-%m-%d %H:%M:%S",
stream=sys.stderr,
)
More Starlette Packages
If you are building server-rendered Starlette apps, these packages fit well with
starlette-hot-reload:
- starlette-tailwindcss: Tailwind CSS integration for Starlette apps
- starlette-html-stories:
Storybook-like development tools for
starlette-htmlcomponents - starlette-html: Python-first HTML DSL for server-rendered UI in Starlette
License
MIT
Metadata
Release files for starlette-hot-reload 0.3.0
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 |
|---|---|---|---|---|
| starlette_hot_reload-0.3.0.tar.gz | 9.9 kB | Without provenance | Details for starlette_hot_reload-0.3.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| starlette_hot_reload-0.3.0-py3-none-any.whl | Python 3 | none | any | Details for starlette_hot_reload-0.3.0-py3-none-any.whl |
Total release size: 22.4 kB
Release files / starlette_hot_reload-0.3.0.tar.gz
| Download URL | starlette_hot_reload-0.3.0.tar.gz |
|---|---|
| Size | 9.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
22e8135a3bfa772aa7e78fb9e58d55dd27449ceed9fa3eb3723c09db701d523e
|
|
BLAKE2b-256 checksum How to use checksums |
579fee3ea1f006a64d2ec1a7315573d57fdda01815bb3ba2c7d2a437b0426260
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.11.4 {"installer":{"name":"uv","version":"0.11.4","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / starlette_hot_reload-0.3.0-py3-none-any.whl
| Download URL | starlette_hot_reload-0.3.0-py3-none-any.whl |
|---|---|
| Size | 12.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
b4b5cfb8a51d12b4186da0f2ef5820ed0b2a4afdc1d13673186eb37752c78172
|
|
BLAKE2b-256 checksum How to use checksums |
cf10dd345d1f5ee69a4369eaca762c43b8e54703ec73aed64824da960976dd67
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.11.4 {"installer":{"name":"uv","version":"0.11.4","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Security for starlette-hot-reload 0.3.0
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.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A 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.