{"id":13724999,"url":"https://github.com/adamchainz/django-watchfiles","last_synced_at":"2025-12-29T23:56:04.711Z","repository":{"id":50701735,"uuid":"473588320","full_name":"adamchainz/django-watchfiles","owner":"adamchainz","description":"Use watchfiles in Django’s autoreloader.","archived":false,"fork":false,"pushed_at":"2024-04-29T21:02:42.000Z","size":150,"stargazers_count":77,"open_issues_count":11,"forks_count":8,"subscribers_count":6,"default_branch":"main","last_synced_at":"2024-05-01T12:53:35.965Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/adamchainz.png","metadata":{"files":{"readme":"README.rst","changelog":"CHANGELOG.rst","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":".github/CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":".github/SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-03-24T12:04:18.000Z","updated_at":"2024-05-03T20:52:30.994Z","dependencies_parsed_at":"2023-10-16T23:56:41.557Z","dependency_job_id":"659bbcab-0756-4fff-9c08-e2035823683e","html_url":"https://github.com/adamchainz/django-watchfiles","commit_stats":{"total_commits":2,"total_committers":1,"mean_commits":2.0,"dds":0.0,"last_synced_commit":"5fa0a4b645b3cd06ae003d48aeba6ea72122b8ca"},"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/adamchainz%2Fdjango-watchfiles","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/adamchainz%2Fdjango-watchfiles/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/adamchainz%2Fdjango-watchfiles/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/adamchainz%2Fdjango-watchfiles/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/adamchainz","download_url":"https://codeload.github.com/adamchainz/django-watchfiles/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":224645166,"owners_count":17346090,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-03T01:02:09.306Z","updated_at":"2025-12-29T23:56:04.699Z","avatar_url":"https://github.com/adamchainz.png","language":"Python","funding_links":[],"categories":["Python"],"sub_categories":[],"readme":"=================\ndjango-watchfiles\n=================\n\n.. image:: https://img.shields.io/github/actions/workflow/status/adamchainz/django-watchfiles/main.yml.svg?branch=main\u0026style=for-the-badge\n   :target: https://github.com/adamchainz/django-watchfiles/actions?workflow=CI\n\n.. image:: https://img.shields.io/badge/Coverage-100%25-success?style=for-the-badge\n   :target: https://github.com/adamchainz/django-watchfiles/actions?workflow=CI\n\n.. image:: https://img.shields.io/pypi/v/django-watchfiles.svg?style=for-the-badge\n   :target: https://pypi.org/project/django-watchfiles/\n\n.. image:: https://img.shields.io/badge/code%20style-black-000000.svg?style=for-the-badge\n   :target: https://github.com/psf/black\n\n.. image:: https://img.shields.io/badge/pre--commit-enabled-brightgreen?logo=pre-commit\u0026logoColor=white\u0026style=for-the-badge\n   :target: https://github.com/pre-commit/pre-commit\n   :alt: pre-commit\n\nMake Django’s autoreloader more efficient by watching for changes with `watchfiles \u003chttps://watchfiles.helpmanual.io/\u003e`__.\n\nRead more in `the introductory post \u003chttps://adamj.eu/tech/2025/09/22/introducing-django-watchfiles/\u003e`__, or below.\n\n----\n\n**Improve your Django and Git skills** with `my books \u003chttps://adamj.eu/books/\u003e`__.\n\n----\n\nRequirements\n------------\n\nPython 3.10 to 3.14 supported.\n\nCorrect behaviour for globs requires Python 3.13+ for |Path.full_match()|__, per `Issue #91 \u003chttps://github.com/adamchainz/django-watchfiles/issues/91\u003e`__.\n\n.. |Path.full_match()| replace:: ``Path.full_match()``\n__ https://docs.python.org/3/library/pathlib.html#pathlib.PurePath.full_match\n\nDjango 4.2 to 6.0 supported.\n\nInstallation\n------------\n\n1. Install with **pip**:\n\n   .. code-block:: sh\n\n       python -m pip install django-watchfiles\n\n2. Add django-watchfiles to your ``INSTALLED_APPS``:\n\n   .. code-block:: python\n\n       INSTALLED_APPS = [\n           ...,\n           \"django_watchfiles\",\n           ...,\n       ]\n\nThat’s it! 😅\n\nTry installing `django-browser-reload \u003chttps://github.com/adamchainz/django-browser-reload\u003e`__ as well, to make your browser automatically reload the page when changes are detected.\n\nUsage\n-----\n\ndjango-watchfiles will be automatically used by Django’s |runserver command|__.\nYou can tell this because ``runserver`` will list ``WatchfilesReloader`` as the watcher class:\n\n.. |runserver command| replace:: ``runserver`` command\n__ https://docs.djangoproject.com/en/stable/ref/django-admin/#runserver\n\n.. code-block:: shell\n\n   $ ./manage.py runserver\n   Watching for file changes with WatchfilesReloader\n   ...\n\n(Rather than the default ``StatReloader``.)\n\n``WatchfilesReloader`` provides the following advantages:\n\n* **Much lower CPU usage**\n\n  Django’s default ``StatReloader`` works by polling all files for changes, sleeping for one second, and looping.\n  Meanwhile, ``WatchfilesReloader`` avoids polling; instead, it asks the operating system to report any changes to the watched files.\n\n  The difference can be stark and save you significant battery when developing on a device that isn’t connected to a power source.\n  A quick benchmark on a medium-sized project (385,000 lines plus 206 installed packages) using an M1 MacBook showed ``StatReloader`` using **~10%** of a CPU every other second, while ``WatchfilesReloader`` uses **0%**.\n\n* **Reduced reload time**\n\n  ``StatReloader`` can take one second or more to detect changes, while ``WatchfilesReloader`` can take as little as 50 milliseconds.\n  This means that ``runserver`` starts reloading your code more quickly, and you can iterate more rapidly.\n\n* **Batched reloads**\n\n  Sometimes multiple file changes can occur in quick succession, such as when one file is saved and then updated by a formatter, or when multiple files are changed when you ``git switch`` to another branch.\n  In such cases, ``StatReloader`` can trigger multiple reloads, unnecessarily slowing down progress, or it can miss some changes, leading to old code being left running.\n  ``WatchfilesReloader`` instead batches changes, using watchfiles’ `debounce feature \u003chttps://watchfiles.helpmanual.io/api/watch/#:~:text=debounce,-int\u003e`__, so that multiple changes will only trigger a single reload.\n\n  ``WatchfilesReloader`` uses watchfiles’ defaults here, waiting for changes within a 50 millisecond window, and repeating this wait for up to 1600 milliseconds, as long as changes keep occurring.\n  These values provide a good balance between responsiveness and batching.\n\nOn some platforms (Windows Subsystem for Linux, or WSL), watchfiles will fall back to a polling approach.\nThis is still more efficient than ``StatReloader`` though, because it’s implemented in Rust.\n\nwatchfiles has some configuration options which can be configured through environment variables.\nSee the `watchfiles documentation \u003chttps://watchfiles.helpmanual.io/api/watch/#watchfiles.watch\u003e`__ for details.\n\nExample project\n---------------\n\nTo demonstrate and test django-watchfiles in various situations, there is an example project included in the repository.\nOpen |the example directory|__, follow the instructions in its README, and try it out.\n\n.. |the example directory| replace:: the ``example/`` directory\n__ https://github.com/adamchainz/django-watchfiles/tree/main/example\n\nHistory\n-------\n\nDjango’s ``runserver`` started with only the logic for ``StatReloader``, because it’s simple and works on all platforms.\n\nIn Django 1.7 (2014), Django gained support for using the Linux file-watching API ``inotify``, through the `pyinotify package \u003chttps://pypi.org/project/pyinotify/\u003e`__.\nThis provided efficient reloading, but was limited to Linux.\nThis was thanks to Unai Zalakain, Chris Lamb, and Pascal Hartig for that work in `Ticket #9722 \u003chttps://code.djangoproject.com/ticket/9722\u003e`__.\n\nIn Django 2.2 (2019), Django gained support for `Watchman \u003chttps://facebook.github.io/watchman/\u003e`__, a cross-platform file-watching service from Facebook, via the `pywatchman package \u003chttps://pypi.org/project/pywatchman/\u003e`__.\nThis provides efficient reloading on Linux and macOS, but requires developers to install and run the Watchman service separately.\nThanks to Tom Forbes for that work in `Ticket #27685 \u003chttps://code.djangoproject.com/ticket/27685\u003e`__.\n\nUnfortunately, the pywatchman package stopped working on Python 3.10, as reported in its `Issue #970 \u003chttps://github.com/facebook/watchman/issues/970\u003e`__ (2021).\nThis issue remained unfixed for a long time, until March 2024, after the release of Python 3.12.\nIt appears that Watchman and pywatchman are not a priority for maintenance by Facebook.\n\nIn 2022, Samel Colvin released `watchfiles \u003chttps://pypi.org/project/watchfiles/\u003e`__, a new cross-platform file-watching library for Python.\nIt is powered by `Notify \u003chttps://github.com/notify-rs/notify\u003e`__, a popular and established Rust crate.\n(watchfiles is also the Rust-powered rebuild of Samuel’s earlier `watchgod package \u003chttps://pypi.org/project/watchgod/\u003e`__ (2017).)\n\nI created django-watchfiles in 2022 to integrate watchfiles with Django’s autoreloader.\nThe inspiration came from writing about using Watchman in `Boost Your Django DX \u003chttps://adamchainz.gumroad.com/l/byddx\u003e`__ and feeling a bit dismayed that it wasn’t particularly easy, and that it wasn’t (yet) working on Python 3.10.\n\ndjango-watchfiles had its first stable release in 2024.\nI may propose integrating it with Django core at some point, when it’s more established.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fadamchainz%2Fdjango-watchfiles","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fadamchainz%2Fdjango-watchfiles","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fadamchainz%2Fdjango-watchfiles/lists"}