A drop-in Flask health blueprint — /healthz (liveness) + /readyz (readiness) in two lines.
Every service needs the same two endpoints — "are you alive?" and "can you serve?" — yet everyone re-writes them, slightly differently, in every app. flask-vitals is the boring, correct version you register once:
from flask_vitals import vitals
app.register_blueprint(vitals())…and now GET /healthz and GET /readyz answer exactly the way orchestrators
(Kubernetes), load balancers, and external monitors
(Huginn, UptimeRobot, Uptime Kuma) expect.
- Liveness vs. readiness, done right —
/healthzsays the process is up;/readyzsays it can actually serve (its dependencies are reachable). - Injected checks — readiness probes your DB / cache / queue via callables you provide; the library never reaches into your stack.
- Honest status codes —
/readyzreturns503with a per-check breakdown when something is down, so "up but broken" is caught. - Zero config to start, fully tunable — custom paths, an optional version string, any number of named checks.
- Tiny & typed — one module, no dependency beyond Flask,
mypy --strict, 100 % tested. MIT-licensed.
pip install flask-vitals
# or
uv add flask-vitalsfrom flask import Flask
from sqlalchemy import text
from flask_vitals import vitals
app = Flask(__name__)
def db_ok() -> None:
db.session.execute(text("SELECT 1")) # raises → not ready
app.register_blueprint(vitals(checks={"db": db_ok}, version="1.4.2"))| Request | Response | Code |
|---|---|---|
GET /healthz |
{"status": "ok", "version": "1.4.2"} |
200 |
GET /readyz |
{"ready": true, "checks": {"db": true}} |
200 |
GET /readyz |
{"ready": false, "checks": {"db": false}} (db unreachable) |
503 |
A check passes unless it returns False or raises — so a one-liner like
lambda: cache.ping() is a valid check.
| Argument | Default | Purpose |
|---|---|---|
checks |
{} |
{name: callable} readiness probes |
version |
None |
echoed by /healthz when set |
liveness_path |
/healthz |
liveness route |
readiness_path |
/readyz |
readiness route |
name |
"vitals" |
blueprint name (change if registered twice) |
Point an uptime monitor at each app:
- an HTTP monitor on
…/healthz— expected status200→ is it alive? - a keyword monitor on
…/readyzcontaining"ready": true→ is it serving?
That's the UptimeRobot/Uptime-Kuma experience for any Flask app, with no bespoke health code per service.
uv sync
uv run ruff format --check .
uv run ruff check .
uv run mypy
uv run pytestOne module, flask_vitals.blueprint, exposing vitals(...) -> flask.Blueprint.
No global state, no dependency beyond Flask; readiness checks are injected by the
host app, so the library stays decoupled from your stack and trivially testable.
Issues and PRs are welcome! Keep it small and tested:
uv sync- Make your change with a test.
uv run ruff format . && uv run ruff check . && uv run mypy && uv run pytest- Open a PR.
MIT © Clara Vanacker