Skip to main content

Defining and Registering Blueprints

When your Flask application grows, keeping all routes and logic in a single file becomes unmanageable. The Blueprint class allows you to group related views, error handlers, and other functions into distinct components that are registered with the main application later.

Basic Blueprint Definition and Registration

To use a blueprint, define it in a module and then register it on your Flask application instance.

# auth.py
from flask import Blueprint

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

@bp.route("/login", methods=("GET", "POST"))
def login():
return "Login Page"

In your application factory or main module, register the blueprint:

# __init__.py
from flask import Flask
from . import auth

def create_app():
app = Flask(__name__)

# Register the blueprint
app.register_blueprint(auth.bp)

return app

When you register a blueprint, Flask records the operations (like @bp.route) and replays them on the application. By default, the blueprint's name is prepended to all endpoints (e.g., url_for("auth.login")).

Organizing with URL Prefixes

You can use the url_prefix parameter to namespace all routes within a blueprint. This can be defined when creating the Blueprint or overridden when registering it.

# Defined at creation
bp = Blueprint("admin", __name__, url_prefix="/admin")

# Overridden or added at registration
app.register_blueprint(bp, url_prefix="/v1/admin")

If both are provided, the registration prefix is prepended to the blueprint's prefix. For example, a route @bp.route("/users") would be accessible at /v1/admin/users.

Using Subdomains for Routing

Blueprints can match specific subdomains. This requires setting SERVER_NAME in your configuration and enabling subdomain_matching.

app = Flask(__name__)
app.config["SERVER_NAME"] = "example.test"
app.subdomain_matching = True

# Routes in this blueprint only match api.example.test
api_bp = Blueprint("api", __name__, subdomain="api")

@api_bp.route("/")
def index():
return "API Home"

app.register_blueprint(api_bp)

Nesting Blueprints

Flask supports nesting blueprints by registering one blueprint on another. The child blueprint inherits the parent's URL prefix and subdomain.

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

@child.route("/info")
def info():
return "Child Info"

# Register child on parent
parent.register_blueprint(child)

# Register parent on app
app.register_blueprint(parent)
# The route is now accessible at /parent/child/info

If both blueprints define a subdomain, they are combined. For a parent with subdomain="user" and a child with subdomain="api", the resulting subdomain is api.user.example.test.

Registering a Blueprint Multiple Times

You can register the same blueprint instance multiple times on the same application, provided you give each registration a unique name. This is useful for versioning or mounting the same logic at different paths.

bp = Blueprint("api", __name__)

@bp.route("/data")
def get_data():
return "Data"

# Register twice with different names and prefixes
app.register_blueprint(bp, name="v1", url_prefix="/v1")
app.register_blueprint(bp, name="v2", url_prefix="/v2")

# Endpoints are now "v1.get_data" and "v2.get_data"

Troubleshooting

Dot in Blueprint Name

Blueprint names cannot contain a dot (.). Attempting to initialize a blueprint with a dot in the name will raise a ValueError.

# This will raise ValueError: 'name' may not contain a dot '.' character.
bp = Blueprint("auth.v1", __name__)

Modification After Registration

Once a blueprint is registered on an application, it is considered "locked." Calling setup methods like @bp.route, bp.before_request, or bp.errorhandler after registration will raise an AssertionError.

app.register_blueprint(bp)

# This will raise AssertionError
@bp.route("/late")
def late_route():
return "Too late"

Duplicate Registration Names

Registering two different blueprints with the same name, or the same blueprint twice without providing a unique name parameter, will raise a ValueError.

bp1 = Blueprint("common", __name__)
bp2 = Blueprint("common", __name__)

app.register_blueprint(bp1)
# This will raise ValueError because "common" is already taken
app.register_blueprint(bp2)