---
title: "💭 Automatic browser reloading in FastAPI"
description: "!https://gist.github.com/vrslev/6d0602bfa939a01844f645c608afb85a"
date: 2023-10-08
published: true
tags:
  - webdev
  - fastapi
  - thought
template: link
---


<div class="embed-card embed-card-external embed-card-provider-github" data-needs-code-css="true">
  <div class="embed-card-rich">
<div data-needs-code-css="true"><div class="embed-gist">
  <div class="embed-gist-header">
    <a href="https://gist.github.com/vrslev/6d0602bfa939a01844f645c608afb85a" target="_blank" rel="noopener noreferrer">main.py</a>
    <span class="embed-gist-language">python</span>
  </div>
<pre class="chroma"><code><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">os</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">arel</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">fastapi</span> <span class="kn">import</span> <span class="n">FastAPI</span><span class="p">,</span> <span class="n">Request</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">fastapi.templating</span> <span class="kn">import</span> <span class="n">Jinja2Templates</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">app</span> <span class="o">=</span> <span class="n">FastAPI</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="n">templates</span> <span class="o">=</span> <span class="n">Jinja2Templates</span><span class="p">(</span><span class="s2">&#34;templates&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">if</span> <span class="n">_debug</span> <span class="o">:=</span> <span class="n">os</span><span class="o">.</span><span class="n">getenv</span><span class="p">(</span><span class="s2">&#34;DEBUG&#34;</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="n">hot_reload</span> <span class="o">=</span> <span class="n">arel</span><span class="o">.</span><span class="n">HotReload</span><span class="p">(</span><span class="n">paths</span><span class="o">=</span><span class="p">[</span><span class="n">arel</span><span class="o">.</span><span class="n">Path</span><span class="p">(</span><span class="s2">&#34;.&#34;</span><span class="p">)])</span>
</span></span><span class="line"><span class="cl">    <span class="n">app</span><span class="o">.</span><span class="n">add_websocket_route</span><span class="p">(</span><span class="s2">&#34;/hot-reload&#34;</span><span class="p">,</span> <span class="n">route</span><span class="o">=</span><span class="n">hot_reload</span><span class="p">,</span> <span class="n">name</span><span class="o">=</span><span class="s2">&#34;hot-reload&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">app</span><span class="o">.</span><span class="n">add_event_handler</span><span class="p">(</span><span class="s2">&#34;startup&#34;</span><span class="p">,</span> <span class="n">hot_reload</span><span class="o">.</span><span class="n">startup</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">app</span><span class="o">.</span><span class="n">add_event_handler</span><span class="p">(</span><span class="s2">&#34;shutdown&#34;</span><span class="p">,</span> <span class="n">hot_reload</span><span class="o">.</span><span class="n">shutdown</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">templates</span><span class="o">.</span><span class="n">env</span><span class="o">.</span><span class="n">globals</span><span class="p">[</span><span class="s2">&#34;DEBUG&#34;</span><span class="p">]</span> <span class="o">=</span> <span class="n">_debug</span>
</span></span><span class="line"><span class="cl">    <span class="n">templates</span><span class="o">.</span><span class="n">env</span><span class="o">.</span><span class="n">globals</span><span class="p">[</span><span class="s2">&#34;hot_reload&#34;</span><span class="p">]</span> <span class="o">=</span> <span class="n">hot_reload</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nd">@app.get</span><span class="p">(</span><span class="s2">&#34;/&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">index</span><span class="p">(</span><span class="n">request</span><span class="p">:</span> <span class="n">Request</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">templates</span><span class="o">.</span><span class="n">TemplateResponse</span><span class="p">(</span><span class="s2">&#34;index.html&#34;</span><span class="p">,</span> <span class="n">context</span><span class="o">=</span><span class="p">{</span><span class="s2">&#34;request&#34;</span><span class="p">:</span> <span class="n">request</span><span class="p">})</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># run:</span>
</span></span><span class="line"><span class="cl"><span class="c1"># DEBUG=true uvicorn main:app --reload</span>
</span></span></code></pre>
</div>
</div>
  </div>
</div>


I just discovered [arel](https://pypi.org/project/arel/) for hot reloading python applications when content changes from this snippet that implements it for fatapi.

On app startup add the `/hot-reload` routes if in **DEBUG** mode.

``` python

import os

import arel
from fastapi import FastAPI, Request
from fastapi.templating import Jinja2Templates

app = FastAPI()
templates = Jinja2Templates("templates")

if _debug := os.getenv("DEBUG"):
    hot_reload = arel.HotReload(paths=[arel.Path(".")])
    app.add_websocket_route("/hot-reload", route=hot_reload, name="hot-reload")
    app.add_event_handler("startup", hot_reload.startup)
    app.add_event_handler("shutdown", hot_reload.shutdown)
    templates.env.globals["DEBUG"] = _debug
    templates.env.globals["hot_reload"] = hot_reload


@app.get("/")
def index(request: Request):
    return templates.TemplateResponse("index.html", context={"request": request})

# run:
# DEBUG=true uvicorn main:app --reload
```

install `arel` and make sure you have `uvicorn[standard]` for websocket support.

``` text
fastapi
uvicorn[standard]
arel
jinja2
```

In the template, load the script when in debug mode.

``` html
<body>
  {% block content %}{% endblock %}

  <!-- Hot reload script -->
  {% if DEBUG %} {{ hot_reload.script(url_for('hot-reload')) | safe }} {% endif
  %}
</body>
```

!!! note

    This post is a <a href="/thoughts/" class="wikilink" data-title="Thoughts" data-description="These are generally my thoughts on a web page or some sort of url, except a rare few don&#39;t have a link. These are dual published off of my..." data-date="2024-04-01">thought</a>. It's a short note that I make
    about someone else's content online <a href="/tags/thoughts/" class="hashtag-tag" data-tag="thoughts" data-count=2 data-reading-time=3 data-reading-time-text="3 minutes">#thoughts</a>
