Skip to main content

Introduction to Blueprints

As your Flask application grows, keeping all your routes and logic in a single file becomes difficult to maintain. Blueprints allow you to organize your application into distinct, modular components that can be developed independently and registered on the main application later.

In this tutorial, you will build a modular authentication system by creating a Blueprint, defining routes within it, and registering it on a Flask application.

Prerequisites

  • Flask installed in your environment.
  • A basic understanding of Flask routes and the Flask application object.

Step 1: Create a Blueprint

A Blueprint is an object that allows you to define routes and other application functions without requiring an application object immediately. It "records" these operations to be replayed when the blueprint is eventually registered.

Create a file named auth.py and define your blueprint:

from flask import Blueprint

bp = Blueprint("auth", __name__, url_prefix="/auth")

The Blueprint constructor requires two positional arguments:

  1. name: The name of the blueprint (e.g., "auth"). This is used for namespacing endpoints in url_for. It cannot contain dots.
  2. import_name: Usually set to __name__. This helps Flask locate resources like templates or static files relative to the blueprint's file.

The url_prefix argument is optional but highly recommended. It prepends /auth to every route defined in this blueprint, keeping your URL structure organized.

Step 2: Define Routes on the Blueprint

You define routes on a blueprint using the same decorators you would use on a standard Flask app object, such as @bp.route.

Add a login route to your auth.py file:

@bp.route("/login", methods=("GET", "POST"))
def login():
# In a real app, you would handle form validation and database lookups here.
return "Login Page"

@bp.route("/logout")
def logout():
return "Logged Out"

Because you set url_prefix="/auth", the login function will handle requests to /auth/login.

Step 3: Register the Blueprint on the Application

To make the blueprint's routes active, you must register it with your Flask application instance using app.register_blueprint(). This is typically done inside an application factory function.

In your __init__.py (or main application file):

from flask import Flask
from . import auth

def create_app():
app = Flask(__name__)

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

return app

When app.register_blueprint(auth.bp) is called, Flask replays all the "recorded" operations (like the @bp.route decorators) onto the app object.

Step 4: Generate URLs with Namespacing

When using blueprints, Flask namespaces your endpoints. To generate a URL for a blueprint route using url_for, you must prepend the blueprint's name followed by a dot.

from flask import url_for

# This generates '/auth/login'
login_url = url_for("auth.login")

If you are inside a view function of the same blueprint, you can use a shortcut by starting with a dot: url_for(".login").

Step 5: Use App-Wide vs Blueprint-Specific Handlers

Blueprints allow you to define logic that runs only for its own routes, or logic that runs for every request in the entire application.

  • @bp.before_request: Runs before every request that is handled by this blueprint.
  • @bp.before_app_request: Runs before every request to the application, regardless of which blueprint (or the main app) handles it.

Example from flaskr/auth.py:

@bp.before_app_request
def load_logged_in_user():
# This runs before every single request in the app
# to ensure g.user is always populated if a session exists.
pass

Step 6: Nest Blueprints for Complex Hierarchies

For very large applications, you can register blueprints on other blueprints. This allows you to build a deep hierarchy of components.

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

# Register child on parent
parent.register_blueprint(child)

# Register parent on app
app.register_blueprint(parent)

In this setup, a route defined as @child.route("/info") would be accessible at /parent/child/info.

Summary and Next Steps

You have successfully organized your application logic into a modular Blueprint. By using blueprints, you can:

  • Keep related logic grouped together.
  • Use URL prefixes to avoid route collisions.
  • Share common logic (like authentication checks) across specific sets of routes.

Next, you might explore adding a static_folder or template_folder to your Blueprint constructor to make your component truly self-contained with its own assets and HTML templates. Remember that blueprint templates have lower precedence than the main application's templates folder, allowing you to override them if needed.