How to hot reload FastAPI and Flask apps on HTML, CSS, and Javascript changes


November 16, 2023 / 5 min read / 7,900 views, 1 likes, 1 comments

Last updated: November 19, 2023

Tags: python, fastapi, flask, html, css, javascript, uvicorn, gunicorn, jinja2, browser-sync


hot reload

Getting instant feedback for code changes is essential when developing a web application. Typical workflows for Python web applications involve a hot-reload functionality for the development web server that will automatically restart the server when changes to python files are detected. However, the server will not automatically restart when changes to HTML, CSS, or JavaScript files are detected. When those files are updated, you must manually restart the server for the changes to occur. Moreover, this typical workflow will not automatically refresh your web browser when you update files, so you must manually refresh the web page to see the changes.

In this tutorial, I'll show you how to automatically hot-reload your FastAPI and Flask projects that use template engines like Jinja with web servers like uvicorn or gunicorn. After reading, you will be able to automatically restart your server and refresh your browser when Python, HTML, CSS, and other files change—no manual intervention required.

Example

You can find bare-bones example code for this tutorial in my GitHub repository named "hot-reload-examples", here. The following video shows the hot reloading in action, using that repository's fastapi example.

Installations

You'll need to perform these installations to get hot reloading working.

For both FastAPI and Flask

  • Node.js
  • npm (usually included with node.js)
  • browser-sync. The following command will install it globally: npm install -g browser-sync

For FastAPI

You can install these with pip install fastapi "uvicorn[standard]" jinja2.

For Flask

You can install these with pip install flask gunicorn.

The steps

Here are the steps to get hot reloads working for your FastAPI or Flask project.

  1. Run the server with --reload, specifying the files to look for when reloading.

    • FastAPI with uvicorn:

      uvicorn main:app --reload --reload-include="*.html" --reload-include="*.css" --reload-include="*.js"
      

      The above command will run a server on http://localhost:8000 and watch for changes to Python files (default) and CSS, HTML, and JS files (according to the glob patterns we provided).

    • Flask with gunicorn:

      gunicorn main:app --reload --reload-extra-file="templates/index.html" --reload-extra-file="static/styles.css"
      

      The above command will run a server on http://localhost:8000 and watch for changes to Python files (default), templates/index.html, and static/styles.css. Annoyingly, gunicorn currently does not allow you to specify glob patterns, so you must specify each non-python file to watch for changes.

    • Alternatively, you could run Flask with the Flask development server:

      flask --app main:app run --debug --extra-files templates/index.html:static/styles.css
      

      Use ; on Windows to separate the --extra-files instead of :. The above command will run a server on http://localhost:5000 and watch for changes to Python files (default), templates/index.html, and static/styles.css. Annoyingly, like with gunicorn, flask does not allow you to specify glob patterns, so you must specify each non-python file to watch for changes.

  2. In a separate terminal, run browser-sync in watch mode, specifying the address to proxy and the static files path.

    browser-sync 'http://localhost:8000' 'static' --watch --files .
    

    Change the localhost port to the port your server is running on if it differs from 8000. The above command will run a server on http://localhost:3000 and proxy requests to http://localhost:8000 (your server running FastAPI or Flask). It will also forward static files from the static directory (you can change the static files directory with the second argument to browser-sync). Finally, it will watch for changes to all files relative to the working directory and reload the browser when those files change.

    Go to http://localhost:3000.

  3. Turn off caching in your browser

    NOTE: This third step might not be necessary for you. Playing around with browser-sync, it appears to usually not cache static files. However, it doesn't seem like cache-prevention works 100% of the time, so I'll include this option just in case.

    By default, browsers will cache static files. Therefore, you might not see changes to CSS and JavaScript files reflected in the browser, as the browser will use the stale, cached version after the first load. To fix this, you might need to turn off caching in your browser. For Chrome, you can do this with the following steps:

    1. Open the browser to http://localhost:3000
    2. Right-click on the browser page
    3. Click "Inspect" to open dev tools
    4. Navigate to the "Network" tab
    5. Check "Disable cache"

    NOTE: If you do need this step, disabling the cache this way only applies while dev tools remains open.

  4. Update your files as needed and see the changes automatically reflected in the browser—no manual intervention required.

Conclusion

Now, when developing your FastAPI or Flask application, you have the tools to change your Python, HTML, CSS, and Javascript files and see those changes automatically reflected in the browser (http://localhost:3000) without refreshing the page. Furthermore, the techniques shown here should work for any web application with built-in hot-reload functionality—not just the two I showed examples for in this tutorial. Enjoy your easier, more iterative web development experience!


About the author


Theodore Williams

Hi, my name is Teddy Williams. I'm a software developer with a special love for python programming. 🐍👨‍💻 I have a wide range of programming interests including web development, hobby video game development, IoT, data science and just writing scripts to automate everyday boring tasks. I'd love it if you check out some of my other posts or take a look at my portfolio! :)

Thanks for reading this post! 💚 If you like the post, let me know by hitting the icon below, and if you have any questions or comments I'd love to hear them in the comments section. Thanks, and happy coding! 🎉

like post (1) Comments (1)


Log in to comment with your own custom profile. That way you can edit and delete your comments. Plus you can pick out a fun profile picture to show-off next to your comment. 😃🤖👽😻 Not Registered? It's easy! 🤓 Or... fast-comment without a login below (no comment editing/deleting 💩).

User avatar not found

Rich Williams | November 17, 2023 03:50 PM

That is a well-written article. Thanks for sharing!

reply