Skip to content

Django Health Check — Complete Implementation Guide

DodaTech Updated 2026-06-28 5 min read

In this tutorial, you will learn about Django Health Check. We cover key concepts, practical examples, and best practices to help you master this topic.

Django health checks verify database connectivity, cache availability, and application functionality, integrating with django-health-check library and Kubernetes probes through dedicated endpoints.

What You'll Learn

By the end of this tutorial, you will know how to add health checks to Django using the django-health-check library, create custom health checks, configure URLs for Kubernetes probes, and handle dependency failures.

Why It Matters

Django powers many production web applications. Proper health checks ensure Django services work correctly with Kubernetes, load balancers, and monitoring systems.

Real-World Use

DodaTech's Django-based content management system uses django-health-check with custom checks for the database, Redis cache, Elasticsearch, and CDN connectivity.

Django Health Check Learning Path

flowchart LR
  A[Express Health Check] --> B[Django Health Check]
  B --> C[django-health-check]
  B --> D[Custom Checks]
  B --> E[Kubernetes Probes]
  B --> F{You Are Here}
  style F fill:#f90,color:#fff

Installing and Configuring django-health-check

The django-health-check library provides built-in checks for common Django components.

# requirements.txt
django-health-check>=3.16.0

# settings.py
INSTALLED_APPS = [
    # ...
    "health_check",
    "health_check.db",
    "health_check.cache",
    "health_check.storage",
    "health_check.contrib.migrations",
]

# urls.py
from django.urls import path, include

urlpatterns = [
    path("ht/", include("health_check.urls")),
    # ...
]

# GET /ht/ -> 200 {"status": "healthy", "checks": [...]}
# GET /ht/ -> 503 {"status": "unhealthy", "checks": [...]}

Running Built-in Health Checks

The library provides several built-in checks out of the box.

# health_check.db checks database connectivity
# health_check.cache checks cache backend
# health_check.storage checks file storage

# To run checks manually:
from health_check.views import MainView

# The main view returns:
# - HTTP 200 if all checks pass
# - HTTP 503 if any check fails
# - JSON or HTML response based on Accept header

# Example response when healthy:
# {
#     "status": "healthy",
#     "checks": [
#         {"identifier": "DatabaseBackend", "status": "working", "time_taken": 0.01},
#         {"identifier": "CacheBackend", "status": "working", "time_taken": 0.005}
#     ]
# }

# Example response when database is down:
# {
#     "status": "unhealthy",
#     "checks": [
#         {"identifier": "DatabaseBackend", "status": "error",
#          "message": "cannot connect to database", "time_taken": 5.0}
#     ]
# }

Custom Health Check

Create custom health checks for application-specific components.

# checks.py
from health_check.backends import BaseHealthCheckBackend
from health_check.exceptions import HealthCheckException
import requests
from django.conf import settings

class ExternalAPICheck(BaseHealthCheckBackend):
    critical_service = True

    def check_status(self):
        try:
            response = requests.get(
                settings.EXTERNAL_API_HEALTH_URL,
                timeout=5
            )
            if response.status_code != 200:
                raise HealthCheckException(
                    f"External API returned {response.status_code}"
                )
        except requests.ConnectionError:
            raise HealthCheckException("Cannot connect to external API")
        except requests.Timeout:
            raise HealthCheckException("External API health check timed out")

    def identifier(self):
        return "external-api"

class RedisQueueCheck(BaseHealthCheckBackend):
    critical_service = False  # Non-critical dependency

    def check_status(self):
        from django.core.cache import cache
        test_key = "health:test"
        cache.set(test_key, "ok", 5)
        value = cache.get(test_key)
        if value != "ok":
            raise HealthCheckException("Cache read/write test failed")
        cache.delete(test_key)

    def identifier(self):
        return "redis-queue"

# settings.py
HEALTH_CHECK_BACKENDS = [
    "health_check.db.backends.DatabaseBackend",
    "health_check.cache.backends.CacheBackend",
    "myapp.checks.ExternalAPICheck",
    "myapp.checks.RedisQueueCheck",
]

Health Check URLs for Kubernetes Probes

Configure Django URLs for Kubernetes probe endpoints.

# urls.py
from django.urls import path
from django.http import JsonResponse
from health_check.views import MainView

def liveness_probe(request):
    """Returns 200 if the process is alive."""
    return JsonResponse({"status": "alive"})

def readiness_probe(request):
    """Returns 200 only if all critical dependencies are healthy."""
    view = MainView.as_view()
    response = view(request)
    return response

def startup_probe(request):
    """Returns 200 after initialization completes."""
    from django.db import connections
    try:
        connections["default"].ensure_connection()
        return JsonResponse({"status": "started"})
    except Exception:
        return JsonResponse({"status": "starting"}, status=503)

urlpatterns = [
    path("healthz/", liveness_probe, name="liveness"),
    path("readyz/", readiness_probe, name="readiness"),
    path("startupz/", startup_probe, name="startup"),
]

Graceful Shutdown Integration

Handle Django's shutdown signal to mark the service as unhealthy.

# apps.py
from django.apps import AppConfig
import atexit

class HealthAppConfig(AppConfig):
    default_auto_field = "django.db.models.BigAutoField"
    name = "myapp"

    def ready(self):
        self.shutting_down = False

        @atexit.register
        def mark_shutting_down():
            self.shutting_down = True

# middleware.py
import threading

class ShutdownMiddleware:
    shutting_down = threading.Event()

    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        if request.path in ["/healthz/", "/readyz/", "/startupz/"]:
            if self.shutting_down.is_set():
                from django.http import JsonResponse
                return JsonResponse(
                    {"status": "shutting_down"},
                    status=503
                )
        return self.get_response(request)

Common Mistakes

  1. Not registering custom health checks -- Custom checks must be listed in HEALTH_CHECK_BACKENDS settings. The library only discovers built-in checks automatically.

  2. Making health checks too expensive -- Django health checks run on every probe. Keep them lightweight. A database SELECT 1 is fine; a full ORM query over thousands of records is not.

  3. Not distinguishing critical and non-critical dependencies -- Set critical_service=False for non-critical dependencies. A Redis cache failure shouldn't make the entire service unhealthy.

  4. Forgetting to configure database connections -- The database health check requires a working DATABASES configuration. If the database is intentionally offline, remove the DB check.

  5. Not handling Migration checks in production -- The migrations check verifies all migrations are applied. In production during a deployment, this can cause false failures if migrations run after the new code starts.

Practice Questions

  1. What library provides built-in health checks for Django? django-health-check. It includes checks for database, cache, storage, and migrations.

  2. How do you create a custom health check in Django? Subclass BaseHealthCheckBackend, implement check_status() and identifier(), then add the class to HEALTH_CHECK_BACKENDS.

  3. What is the difference between critical_service=True and False? True means the check failure makes the service unhealthy (HTTP 503). False means the failure is reported but doesn't affect overall status.

  4. Challenge: Implement a Django health check that verifies a third-party API is accessible and returns correct data.

class ThirdPartyAPICheck(BaseHealthCheckBackend):
    critical_service = True

    def check_status(self):
        import requests
        try:
            response = requests.get(
                "https://api.example.com/health",
                headers={"Authorization": f"Bearer {settings.API_TOKEN}"},
                timeout=3
            )
            if response.status_code != 200:
                raise HealthCheckException(f"API returned {response.status_code}")
            data = response.json()
            if data.get("status") != "ok":
                raise HealthCheckException("API reports unhealthy")
        except requests.exceptions.RequestException as e:
            raise HealthCheckException(str(e))

    def identifier(self):
        return "third-party-api"

FAQ

Does django-health-check support Django 5.0?

Yes. django-health-check 3.16+ supports Django 3.2 through 5.0.

Can I run health checks without the library?

Yes, create simple views that check what you need. The library adds standardization and built-in checks.

How do I exclude health check URLs from logging?

Add a filter to your Django LOGGING config that skips requests to /ht/, /healthz/, etc.

Should health checks be cached?

No. Health checks must return real-time status. Caching defeats the purpose.

How do I handle health checks for Django channels?

Create a custom check that verifies the channel layer is accessible using channels.layers.get_channel_layer().

Mini Project

Build a Django health check configuration with custom checks for database, cache, external API, and queue, with separate endpoints for Kubernetes liveness, readiness, and startup probes.

# Complete health configuration
import django
from django.conf import settings

settings.configure(
    DATABASES={"default": {"ENGINE": "django.db.backends.sqlite3", "NAME": ":memory:"}},
    INSTALLED_APPS=["health_check", "health_check.db", "health_check.cache"],
    HEALTH_CHECK_BACKENDS=["health_check.db.backends.DatabaseBackend"],
)

django.setup()

# Run health check
from health_check.backends import BaseHealthCheckBackend
from health_check.exceptions import ServiceUnavailable

class CustomHealthCheck(BaseHealthCheckBackend):
    def check_status(self):
        if not self.check_condition():
            raise ServiceUnavailable("Service unavailable")

    def check_condition(self):
        return True

    def identifier(self):
        return "custom-check"

What's Next

Now that you understand Django health checks, learn about Go health check implementation. Then explore Spring Boot Actuator health endpoints.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro