Skip to main content

Nesting Blueprints

Blueprints in this codebase support hierarchical organization through nesting. This allows you to group related functionality into sub-modules while maintaining a clean, structured URL and endpoint namespace.

Hierarchical Registration

The core mechanism for nesting is the Blueprint.register_blueprint method. Instead of registering every blueprint directly on the App, you can register a "child" blueprint on a "parent" blueprint. When the parent is eventually registered on the application, all its nested blueprints are registered recursively.

from flask import Blueprint

parent = Blueprint("parent", __name__)
child = Blueprint("child", __name__)
grandchild = Blueprint("grandchild", __name__)

@grandchild.route("/")
def index():
return "Grandchild"

# Nesting the blueprints
child.register_blueprint(grandchild, url_prefix="/grandchild")
parent.register_blueprint(child, url_prefix="/child")

# Registering the top-level parent on the app
app.register_blueprint(parent, url_prefix="/parent")

In this structure, the grandchild index route will be accessible at /parent/child/grandchild/.

URL Prefix and Subdomain Resolution

Nested blueprints automatically inherit and combine configuration from their parents.

URL Prefixes

URL prefixes are concatenated from the parent down to the child. The implementation in Blueprint.register ensures that slashes are handled correctly when joining prefixes:

# From src/flask/sansio/blueprints.py
if state.url_prefix is not None and bp_url_prefix is not None:
bp_options["url_prefix"] = (
state.url_prefix.rstrip("/") + "/" + bp_url_prefix.lstrip("/")
)

Subdomains

Subdomains are prepended, meaning the child's subdomain becomes a third-level domain (or deeper) relative to the parent's subdomain.

# Example from tests/test_blueprints.py
parent = Blueprint("parent", __name__)
child = Blueprint("child", __name__, subdomain="api")

parent.register_blueprint(child)
app.register_blueprint(parent, subdomain="v1")

# Resulting subdomain: api.v1.example.test

Endpoint Naming and Namespacing

Endpoints in nested blueprints use a dotted notation that reflects the nesting hierarchy. This is critical for generating URLs with url_for.

If you have a blueprint named child nested inside parent, a route named index in the child blueprint will have the endpoint parent.child.index.

Renaming for Multiple Registrations

You can register the same blueprint multiple times under different names or prefixes. This is useful for reusable components. The name parameter in register_blueprint allows you to override the blueprint's internal name for that specific registration instance.

# Example from tests/test_blueprints.py
bp = Blueprint("bp", __name__)
bp2 = Blueprint("bp2", __name__)

@bp.get("/")
def index():
return "Main"

@bp2.get("/")
def sub_index():
return "Sub"

# Register bp2 inside bp with a custom name 'sub'
bp.register_blueprint(bp2, url_prefix="/a", name="sub")

# Register bp twice on the app
app.register_blueprint(bp, url_prefix="/a")
app.register_blueprint(bp, url_prefix="/b", name="alt")

# Resulting endpoints:
# bp.index
# alt.index
# bp.sub.sub_index
# alt.sub.sub_index

Callback Execution Order

When a request matches a route in a nested blueprint, callbacks (like before_request) are executed in order from the application level down to the specific blueprint level.

  1. Application before_request functions.
  2. Parent blueprint before_request functions.
  3. Child blueprint before_request functions.

Teardown and after-request functions execute in the reverse order. This allows parent blueprints to set up context or security constraints that apply to all nested children.

Constraints and Requirements

  • No Self-Nesting: A blueprint cannot be registered on itself. Attempting bp.register_blueprint(bp) will raise a ValueError.
  • Unique Names: Within a single parent (or the app), every registered blueprint must have a unique name. If you need to register the same blueprint object twice, you must provide a unique name in the registration options.
  • Setup Finalization: Once a blueprint has been registered on an application (or another blueprint that is already registered), you can no longer call setup methods like record, add_url_rule, or before_request. Doing so will raise an AssertionError.
  • Dot Restriction: Blueprint names and endpoint names cannot contain dots (.), as the dot is reserved as the separator for the hierarchy.