Skip to content

🚧 Under Construction 🚧

This site is currently under construction. This page is generated by AI and has not undergone thorough review by a human. There may be hallucination!

In fact, for now only /, /reactive, and the llms.txt are carefully crafted by myself.

ASGI — uvicorn-hmr

uvicorn-hmr runs ASGI apps with HMR-enabled module loading, reducing restart time by re-executing only changed modules and their dependents.

Install

pip install uvicorn-hmr
# optional browser auto-refresh
pip install uvicorn-hmr[all]

Run

uvicorn-hmr main:app
# supports common uvicorn options; see `uvicorn-hmr --help`

CLI Options

Standard uvicorn options: host, port, log-level, env-file work the same as in uvicorn.

HMR-specific options:

  • --refresh: Enables auto-refreshing of HTML pages in the browser whenever the server restarts. Useful for demo purposes and visual debugging. Requires fastapi-reloader to be installed (e.g., pip install uvicorn-hmr[all]).
  • --clear: Wipes the terminal before each reload (like Vite's default behavior).
  • --reload-include: Paths to watch (only file or directory paths allowed, not patterns; defaults to current directory if not specified).
  • --reload-exclude: Paths to ignore (only file or directory paths allowed, not patterns).

Note: Unlike uvicorn's reload_include/reload_exclude which support patterns and always include/exclude all Python files by default, uvicorn-hmr only watches the paths you specify and uses reactive file system tracking for automatic dependency detection.

What to expect

  • Reloads on file changes without full process restart.
  • Preserves in-memory objects in unaffected modules and when using reactive primitives.
  • Not a full substitute for process restarts; some resources need a clean restart.

Comparison with uvicorn --reload

Feature uvicorn --reload uvicorn-hmr
Reload on change
Preserve some state ✓ (best effort)
Fine-grained reload
Reactive primitives
Browser refresh ✓ (via fastapi-reloader with --refresh)

Caveats

  • Top-level init runs again when a module is re-executed; keep heavy init in modules you rarely edit.
  • C extensions, process-level singletons, and libraries assuming a fresh process may not be safe to hot-reload.
  • Circular imports or module identity checks can behave unexpectedly after in-place reloads.

Best practices

  • Put DB clients, ML models, or other heavy resources behind factories or in stable modules.
  • Use signals/derived/effects for runtime-changing state.
  • Register disposal hooks for cleanup before a module is re-executed.
  • Keep modules small and initialization idempotent.

Debugging

  • Run uvicorn-hmr --help for options.
  • If behavior looks wrong, isolate in a minimal example; restart the process to reset global/native state when needed.

Example

# main.py
from fastapi import FastAPI

app = FastAPI()

@app.get("/")
def read_root():
    return {"message": "Hello, World!"}
uvicorn-hmr main:app
# with browser auto-refresh (requires `fastapi-reloader` to be installed):
uvicorn-hmr main:app --refresh

See examples/fastapi/ for a concrete example (how to run and what to observe) and docs/reactive/ for reactive primitives that integrate with HMR.