Skip to content

Flask Quickstart

Protect a Flask route with Baldur. No Redis, no Docker, no environment variables. The in-memory fallback covers the whole first run.

Supports Python 3.11–3.13. Assumes you have built a Flask app before.

1. Install

pip install baldur-framework[flask]

2. Wire Baldur into the app

init_flask(app) calls baldur.init() once and installs the request hooks (rate-limit, backpressure, circuit-breaker pre-flight). The /demo route is protected by the marquee @baldur.protected facade:

"""Minimal Flask app wired with Baldur.

``init_flask(app)`` calls ``baldur.init()`` exactly once and installs the
request hooks (rate-limit + backpressure + circuit-breaker pre-flight). The
``/demo`` route is protected by the marquee ``@baldur.protected`` facade.
Zero infrastructure: in-memory fallback, no Redis, no env vars.

Run the server with ``flask run`` from this directory, then
``curl http://127.0.0.1:5000/demo``. See ``docs/getting-started/flask.md``.
"""

from __future__ import annotations

from flask import Flask, jsonify

import baldur
from baldur.adapters.flask import init_flask

app = Flask(__name__)
init_flask(app)


@app.get("/demo")
@baldur.protected("demo")
def demo():
    """Return a JSON payload through Baldur's resilience pipeline."""
    return jsonify({"status": "ok", "service": "demo"})

Baldur does not authenticate your routes

The request hooks add resilience (rate-limit, backpressure, circuit breaker), not authentication. Your app keeps owning endpoint auth (Flask-Login, your own decorators). Baldur's own operational surface (the built-in admin server and Web Console) is access-controlled separately by a key you configure; see that guide for the role model. The Django adapter additionally registers Django permission groups for its own admin/API views; there is no equivalent host-app role system on Flask.

3. Run it

Start the server and call the route:

flask run
curl http://127.0.0.1:5000/demo
# {"status": "ok", "service": "demo"}

That's it. The response just travelled through a circuit breaker.

See Baldur's events

Baldur logs to stdout automatically. Raise the log level to watch circuit breaker and rate-limit events as you exercise the endpoint:

export BALDUR_LOG_LEVEL=INFO   # circuit opened/closed, rate-limit blocks, ...

Verify without a browser

The quickstart ships a smoke test that drives the route through Flask's in-process test client — no server, no infra:

pytest examples/quickstart_flask/test_smoke.py

Browse the full runnable app: examples/quickstart_flask/.

Going to production

The in-memory fallback is single-process only

The zero-config path uses Baldur's in-memory cache. It keeps state in a per-process store, so copying this quickstart into a multi-worker deployment (gunicorn --workers N) does not degrade gracefully: idempotency keys, rate-limit counters, and circuit breaker state diverge silently per worker. That breaks correctness, not just scale. The in-memory store also grows unbounded. This is a hazard, not a tuning knob: give Baldur a shared backend before you run more than one worker.

Point Baldur at Redis so all workers share state. No code changes needed: set one environment variable before starting the server:

pip install baldur-framework[flask,redis]
export BALDUR_REDIS_URL=redis://localhost:6379/0

That is the only addition the production path needs over the quickstart path.