Flask Request Lifecycle Hooks Explained

In Python's Flask framework, the execution lifecycle of an HTTP request is managed through decorator-based hooks that execute code before, after, or at the conclusion of a route handler. Understanding how @app.before_request, @app.after_request, and @app.teardown_request interact is essential for handling tasks like authentication, response header modification, database connection pooling, and error cleanup cleanly without cluttering individual view functions.

The Request Lifecycle Flow

When an HTTP request hits a Flask application, it follows a deterministic path:

  1. The Flask application creates a request context.
  2. @app.before_request functions execute.
  3. The matched route view function processes the request (if not short-circuited).
  4. @app.after_request functions modify the generated response.
  5. @app.teardown_request functions execute to clean up resources.
  6. The response is returned to the client, and the request context is torn down.

1. @app.before_request

The before_request hook executes before every request enters its corresponding view function.

from flask import Flask, g, request, abort

app = Flask(__name__)

@app.before_request
def authenticate_user():
    token = request.headers.get("Authorization")
    if not token and request.endpoint != "login":
        abort(401)
    g.user = {"id": 1, "name": "Alice"}

2. @app.after_request

The after_request hook executes after the view function successfully produces a response, but before that response is sent to the client.

@app.after_request
def add_security_headers(response):
    response.headers["X-Content-Type-Options"] = "nosniff"
    response.headers["X-Frame-Options"] = "DENY"
    return response

3. @app.teardown_request

The teardown_request hook executes at the very end of the request context lifecycle, when the request context is being popped.

@app.teardown_request
def close_db_connection(exception=None):
    db = getattr(g, "_database", None)
    if db is not None:
        db.close()

Comparison of Lifecycle Hooks

Feature before_request after_request teardown_request
Execution Point Before route handler After route handler When context is destroyed
Input Arguments None response exception=None
Must Return None (or Response to halt) response Nothing (ignored)
Runs on Error? No No Yes (guaranteed)
Execution Order Registration order Reverse order Reverse order