Skip to main content

Introduction to Blueprints

Blueprints in this codebase provide a way to organize related views, templates, and static files into modular components. Instead of registering routes directly on a central application object, you define them on a Blueprint instance. This decouples the definition of your application's structure from the actual application creation, enabling cleaner code organization and reusability.

The Blueprint class (found in src/flask/sansio/blueprints.py) inherits from Scaffold, which provides the standard decorators for routing and request lifecycle management.

Core Concepts

Deferred Registration

Unlike the main application object, a Blueprint does not immediately register routes or handlers. Instead, it records these actions as "deferred functions." When you call a decorator like @bp.route, the blueprint stores a lambda or function in its deferred_functions list.

These functions are only executed when the blueprint is formally registered on an application via app.register_blueprint(). This process uses a BlueprintSetupState object to apply the recorded settings to the real application instance.

Namespacing

One of the primary roles of a blueprint is to provide namespacing for endpoints. When a blueprint is registered, its name is prepended to all its endpoints. For example, a view named login in a blueprint named auth becomes accessible via the endpoint auth.login.

Defining and Registering Blueprints

A typical blueprint definition involves specifying a name and an import_name (usually __name__). You can also provide a url_prefix to group all routes under a specific path.

In examples/tutorial/flaskr/auth.py, the authentication module is defined as follows:

from flask import Blueprint, render_template, request, session, url_for, redirect

# Define the blueprint
bp = Blueprint("auth", __name__, url_prefix="/auth")

@bp.route("/login", methods=("GET", "POST"))
def login():
if request.method == "POST":
# ... login logic ...
return redirect(url_for("index"))
return render_template("auth/login.html")

To make these routes active, the blueprint must be registered in the application factory (typically in __init__.py):

def create_app():
app = Flask(__name__)
# ...
from . import auth
app.register_blueprint(auth.bp)
return app

Resource Management

Blueprints can manage their own templates and static files, keeping them isolated from the rest of the application.

  • Templates: Specified via the template_folder argument. Note that blueprint templates have lower precedence than the application's global templates folder.
  • Static Files: Specified via static_folder. If a url_prefix is used, the static files are served from {url_prefix}/{static_url_path}.

Advanced Blueprint Features

Blueprint-Specific Error Handlers

You can define error handlers that only trigger for requests handled by a specific blueprint. This is useful for returning module-specific error pages or JSON responses.

As seen in tests/test_blueprints.py:

frontend = Blueprint("frontend", __name__)

@frontend.errorhandler(403)
def frontend_forbidden(e):
return "frontend says no", 403

@frontend.route("/frontend-no")
def frontend_no():
abort(403)

Application-Wide Hooks

Blueprints also provide methods to register hooks that affect the entire application, not just the blueprint's routes. These methods are prefixed with app_:

  • before_app_request: Runs before every request to the application.
  • app_errorhandler: Registers a global error handler.
  • app_template_filter: Registers a Jinja filter available in all templates.

Nested Blueprints

Blueprints can be registered on other blueprints using the register_blueprint method. This allows for hierarchical organization of complex applications. When nesting, the url_prefix and subdomain settings are concatenated.

parent = Blueprint("parent", __name__, url_prefix="/parent")
child = Blueprint("child", __name__, url_prefix="/child")

parent.register_blueprint(child)
# Child routes will now be prefixed with /parent/child

Constraints and Requirements

  • Immutability After Registration: Once a blueprint has been registered on an application, it cannot be modified. Calling setup methods like route() or before_request() after registration will raise an AssertionError.
  • Naming Restrictions: The name of a blueprint cannot contain a dot (.), as dots are used to separate the blueprint name from the endpoint name in url_for.
  • Unique Names: Each blueprint must have a unique name within an application. If you need to register the same blueprint multiple times, you must provide a unique name during registration using the name parameter in register_blueprint.