Skip to main content

Hot reload for Starlette app with smart asset updates and HTML injection

Project description

starlette-hot-reload

Hot reload for Starlette templates and static files

PyPI - Version PyPI - Python Version PyPI - License

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.

Demo

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:

License

MIT

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

starlette_hot_reload-0.3.0.tar.gz (9.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

starlette_hot_reload-0.3.0-py3-none-any.whl (12.6 kB view details)

Uploaded Python 3

File details

Details for the file starlette_hot_reload-0.3.0.tar.gz.

File metadata

  • Download URL: starlette_hot_reload-0.3.0.tar.gz
  • Upload date:
  • Size: 9.9 kB
  • Tags: Source
  • Uploaded using 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}

File hashes

Hashes for starlette_hot_reload-0.3.0.tar.gz
Algorithm Hash digest
SHA256 22e8135a3bfa772aa7e78fb9e58d55dd27449ceed9fa3eb3723c09db701d523e
MD5 99ec725437fd31b6455a3172ef8bd6c7
BLAKE2b-256 579fee3ea1f006a64d2ec1a7315573d57fdda01815bb3ba2c7d2a437b0426260

See more details on using hashes here.

File details

Details for the file starlette_hot_reload-0.3.0-py3-none-any.whl.

File metadata

  • Download URL: starlette_hot_reload-0.3.0-py3-none-any.whl
  • Upload date:
  • Size: 12.6 kB
  • Tags: Python 3
  • Uploaded using 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}

File hashes

Hashes for starlette_hot_reload-0.3.0-py3-none-any.whl
Algorithm Hash digest
SHA256 b4b5cfb8a51d12b4186da0f2ef5820ed0b2a4afdc1d13673186eb37752c78172
MD5 20c889d22766f08e3d81dcc027a4b3de
BLAKE2b-256 cf10dd345d1f5ee69a4369eaca762c43b8e54703ec73aed64824da960976dd67

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page