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.