CLI tool
mwarkentin/django-watchman avatar
mwarkentin/django-watchman

django-watchman: a status endpoint that checks the services behind Django

django-watchman exposes a status endpoint for your backing services like databases, caches, etc.

546 stars64 forksPythonBSD-3-Clause

At a glance

What is it?
django-watchman exposes a JSON endpoint that reports whether the databases, caches, storage and email behind a Django site are actually working, with an HTML dashboard, token protection and a bare 200/500 view for load balancers. It is a health check you can point an external monitor at without wiring up a full observability stack.
Who is it for?
django-watchman fits a Django team that needs a simple external liveness and dependency check, including a project that has no APM or metrics stack and does not want one. It is the wrong tool if you need latency, error rates or traces, because it reports ok or not ok rather than measurements, and the wrong tool for a service where a storage write on every probe is itself too expensive.
Can I use it commercially?
Yes. BSD-3-Clause is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 3 days ago.
What is it written in?
Mainly Python, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The problem is that an HTTP 200 from Django says almost nothing

django-watchman exposes a status endpoint for your backing services like databases, caches and so on. The problem it solves is a familiar one in operations. A Django process returns HTTP 200 as long as the WSGI server is up, which says nothing about whether the database connection still works, whether the cache is reachable, or whether the storage backend has credentials that expired. A monitoring system that pings the site gets a green light in exactly the situation where users are seeing errors. This package turns the question around. Instead of asking whether the process is alive, it asks whether the dependencies are usable, and answers with a JSON document that names each one. The audience is a Django team that wants an endpoint an external monitor such as a hosted ping service can call, rather than something they have to build and maintain themselves.

Four endpoints, and why the probe path is kept cheap

Including `watchman.urls` gives you three endpoints, and the bare status view is added separately in your own `urls.py`. The table in the README lays them out. `/watchman/` returns a JSON response with full check results and requires authentication. `/watchman/dashboard/` is a human-friendly HTML dashboard and also requires authentication. `/watchman/ping/` returns `pong`, runs no checks at all, and is a liveness probe with no auth. `/watchman/bare/` returns an empty response with HTTP 200 or 500, has no auth, and you wire it up manually via `watchman.views.bare_status`. That separation is the design decision worth understanding. A liveness probe that runs a database query every few seconds is a load generator pointed at your production database, so the cheap endpoints exist to be polled aggressively and the expensive ones to be polled rarely.

One feature on the list is easy to overlook: APM integration to suppress tracing for health check endpoints, with Datadog and New Relic named. The reason it is on the list is that health checks are the highest-volume, lowest-value requests your application receives. If every APM agent traces them, the probe traffic dilutes the traces you actually want, inflates your bill, and can push a service over an APM sampling or rate limit. The README also lists a bare status view, a minimal HTTP 200/500 response for load balancers, as a separate concept from the ping endpoint, which suggests the author has thought about the difference between what a load balancer needs and what a human needs to see. The dashboard is the human answer, the JSON is the machine answer, and the bare view is the least invasive of the three.

The built-in checks are enabled by default, except email

Four checks ship with the package and three of them are on by default. The databases check verifies connectivity for each database in `DATABASES`. The caches check sets, gets and deletes a test key in each cache from `CACHES`. The storage check writes, reads and deletes a test file using `default_storage`. The email check sends a test email and is disabled by default since it may incur costs with third-party providers, and you enable it and other paid checks with `WATCHMAN_ENABLE_PAID_CHECKS = True`, or customize the full list with the `WATCHMAN_CHECKS` setting. Note what each check actually does rather than what its name suggests. The cache check is a write, the storage check is a write, and both mutate the system they are inspecting.

Token protection is the default, and the token travels as a query parameter

The configuration table shows how the endpoint is protected. `WATCHMAN_TOKENS` holds comma-separated tokens to protect the endpoint, `WATCHMAN_TOKEN_NAME` sets a custom GET parameter name for the token with a default of `watchman-token`, and `WATCHMAN_AUTH_DECORATOR` is the dotted path to a custom auth decorator with a default of `watchman.decorators.token_required`. The decorator being replaceable is the detail that matters in practice. If your monitoring provider can send a header, you can write a decorator that reads the header instead, which keeps the token out of access logs and proxy logs where a query parameter ends up. `WATCHMAN_ERROR_CODE` sets the HTTP status code used for the failure response, `WATCHMAN_DATABASES` and `WATCHMAN_CACHES` narrow which entries are checked, and the documentation covers custom checks for anything else you want to probe.

Installing and wiring it takes three edits

The quickstart is short. Install the package:

bash
    pip install django-watchman

Or with uv:

bash
    uv add django-watchman

Then add `watchman` to your `INSTALLED_APPS` setting:

python
    INSTALLED_APPS = (
        ...
        'watchman',
    )

And include the watchman URLconf in your project `urls.py`:

python
    re_path(r'^watchman/', include('watchman.urls')),

The dependency footprint is minimal. The packaging metadata declares a single runtime dependency, django>=4.2, and requires Python 3.10 or newer, with classifiers for Django 4.2, 5.1 and 5.2 and Python 3.10 through 3.14. The build backend is hatchling and the version is dynamic, read from `watchman/__init__.py`.

The JSON shape and the command line share one check set

Starting the development server and visiting `http://127.0.0.1:8000/watchman/` gives a JSON response of the backing service statuses:

json
    {
        "databases": [
            {
                "default": {
                    "ok": true
                }
            }
        ],
        "caches": [
            {
                "default": {
                    "ok": true
                }
            }
        ],
        "storage": {"ok": true}
    }

The shape is worth noting because it is what a monitor has to parse. Databases and caches are arrays, with one entry per alias holding an `ok` flag, while storage is a flat object with a single `ok` key. That inconsistency is a small thing that matters if you write a generic parser across services, since the result for a database is nested one level deeper than the result for storage. The full check result also carries the failure detail when a check does not pass, which is what makes the endpoint useful for diagnosis and not just for alerting.

The checks can also run from the command line:

bash
    python manage.py watchman

You can use `-v 2` for verbose output, `-c` to run specific checks, or `-s` to skip checks. That is the same check machinery that serves the endpoint, which means you can use the command in a cron job or a container healthcheck without an HTTP request, and you can select a subset of checks when the full set is too expensive. The repository layout also shows the pieces around it: a `watchman/` package with `checks/` modules for each service type, a `sample_project/` used by the Dockerfile, a `tests/` directory, and a `justfile` that wraps the development commands:

bash
# Run tests
test:
    uv run coverage run --parallel --source watchman -m pytest

# Build and run sample project with docker
run:
    docker build -t watchman .
    docker run -it -p 8000:8000 watchman

The Dockerfile builds from python:3.14-slim, installs uv from the ghcr.io image, and runs the sample project's server on port 8000, which is the quickest way to see the dashboard without wiring up a project of your own.

Where django-watchman is the wrong tool

Three limits are concrete. The first is that a health check that writes is not free, and the cache and storage checks both mutate state on every call. A storage check that writes and deletes a file on every probe turns your monitoring into a write workload on the object store, which on a metered provider is a bill that scales with probe frequency, and it can fail for reasons that have nothing to do with the application, such as an eventual-consistency delay or a bucket policy that permits reads but not writes. The second is that the output is binary. You get ok or not ok, which tells you that something broke but not how slow it got, so a service degrading from 50 milliseconds to 5 seconds stays green until it fails outright. The third is the query-parameter token default, which is the weakest of the available protections since tokens in URLs land in access logs and proxy logs. If you need rate limits, latency percentiles or a historical view, you want a monitoring stack rather than this endpoint.

The alternative is an APM health check with metrics

The realistic alternative is the health check built into an application performance monitoring agent, and the difference in approach is what gets measured. An APM check answers the same yes-or-no question but sits next to a stream of latency and error data, so a failure can be correlated with what changed, and the same agent can suppress its own tracing on the probe path, which is what django-watchman's APM integration does by hand for Datadog and New Relic. django-watchman is the lighter option: one Django dependency, one endpoint, and checks you can extend in Python. The trade-off is what you lose. Without a metrics store you have no history, so an intermittent failure that clears before the next probe leaves no trace, and a bare HTTP 200 or 500 tells a load balancer nothing about whether the service is degraded rather than down.

Editorial conclusion

django-watchman fits a Django team that needs a simple external liveness and dependency check, including a project that has no APM or metrics stack and does not want one. It is the wrong tool if you need latency, error rates or traces, because it reports ok or not ok rather than measurements, and the wrong tool for a service where a storage write on every probe is itself too expensive. Before you adopt it, set WATCHMAN_TOKENS before exposing the endpoint, since the JSON and dashboard views require a token by default, and check which checks run against your production environment, because the storage check writes and deletes a file on every request.

Frequently asked questions

How do I install django-watchman?

Run `pip install django-watchman`, or `uv add django-watchman`. It requires Python 3.10 or newer and Django 4.2 or newer, and its only runtime dependency is Django itself.

Which endpoints does django-watchman provide?

Including `watchman.urls` gives `/watchman/` for JSON results, `/watchman/dashboard/` for an HTML dashboard, and `/watchman/ping/` which returns `pong` and runs no checks. A bare status view returning HTTP 200 or 500 is added separately via `watchman.views.bare_status`.

How do I protect the django-watchman endpoint?

Set `WATCHMAN_TOKENS` to a comma-separated list of tokens. The token is read from a GET parameter named `watchman-token` by default, which you can change with `WATCHMAN_TOKEN_NAME`, and the whole check can be replaced with `WATCHMAN_AUTH_DECORATOR`.

Can I run django-watchman checks from the command line?

Yes, run `python manage.py watchman`. Use `-v 2` for verbose output, `-c` to run specific checks, or `-s` to skip checks, and the same checks back the JSON endpoint.

Official sources

  1. Issues
  2. License: BSD-3-Clause
  3. mwarkentin/django-watchman on GitHub
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/mwarkentin-django-watchman.svg)](https://hysenlabs.com/projects/mwarkentin-django-watchman)

Was this useful?