Flask Blueprints
## Blueprint
When an application has only one file, it's acceptable to have all routes written together.
But as functionality growsβuser module, article module, admin backendβthe code can become difficult to maintain.
Blueprint is the modular solution provided by Flask, allowing you to split your application into independent functional units.
* * *
## Why Blueprints Are Needed
Core problems solved by blueprints:
* Code Organization: Group related routes, templates, and static files together
* Reusability: The same blueprint can be registered to different applications, or registered multiple times (with different prefixes)
* Team Collaboration: Different developers can be responsible for different blueprint modules, reducing conflicts

* * *
## Creating a Blueprint
Blueprints are created using the Blueprint class, with usage very similar to Flaskβsame route decorator, same view function writing style:
## Example
# File path: auth.py (User Authentication Blueprint)
from flask import Blueprint, render_template, request, session, redirect, url_for
# Create blueprint instance
# First parameter "auth" is the blueprint's name (used for url_for references)
# __name__ tells the blueprint where to look for templates and static files
bp = Blueprint("auth", __name__)
# Use bp.route in the blueprint, not app.route
@bp.route("/login", methods=["GET","POST"])
def login():
if request.method=="POST":
username = request.form.get("username","")
if username:
session= username
return redirect(url_for("blog.index"))
return render_template("auth/login.html")
@bp.route("/register", methods=["GET","POST"])
def register():
if request.method=="POST":
username = request.form.get("username","")
if username:
return redirect(url_for("auth.login"))
return render_template("auth/register.html")
@bp.route("/logout")
def logout():
session.clear()
return redirect(url_for("blog.index"))
## Example
# File path: blog.py (Blog Blueprint)
from flask import Blueprint, render_template
bp = Blueprint("blog", __name__)
@bp.route("/")
def index():
# Simulate article data
posts =[
{"title": "Flask Getting Started","author": ""},
{"title": "Blueprint Detailed Explanation","author": ""},
]
return render_template("blog/index.html", posts=posts)
@bp.route("/create", methods=["GET","POST"])
def create():
return render_template("blog/create.html")
* * *
## Registering Blueprints
Blueprints don't take effect automatically after creation; they need to be registered in the application:
## Example
# File path: app.py
from flask import Flask
from auth import bp as auth_bp
from blog import bp as blog_bp
app = Flask( __name__ )
app.secret_key="dev-secret-key"
# Register blueprints to the application
# url_prefix: Add a uniform prefix to all routes in the blueprint
app.register_blueprint(auth_bp, url_prefix="/auth")
# auth blueprint routes become: /auth/login, /auth/logout, /auth/register
app.register_blueprint(blog_bp)
# blog blueprint has no prefix, routes remain: /, /create
Complete routing table after registration:
| URL | Blueprint | endpoint (used by url_for) |
| --- | --- | --- |
| / | blog | blog.index |
| /create | blog | blog.create |
| /auth/login | auth | auth.login |
| /auth/register | auth | auth.register |
| /auth/logout | auth | auth.logout |
> After registering blueprints, the endpoint in url_for() needs to be prefixed with the blueprint name, e.g., url_for("auth.login") instead of url_for("login").
* * *
## Special Usage of url_for in Blueprints
Within the same blueprint, you can use relative references starting with a dot:
## Example
# Inside auth.py, using relative references is more concise
@bp.route("/")
def index():
# Relative reference within the same blueprint (starts with .)
login_url = url_for(".login")# Equivalent to url_for("auth.login")
register_url = url_for(".register")# Equivalent to url_for("auth.register")
# Cross-blueprint references require the full endpoint
blog_url = url_for("blog.index")# Reference to blog blueprint's index
* * *
## Templates and Static Files in Blueprints
Blueprints can also have their own templates and static files.
When a blueprint has its own template folder, Flask first searches in the application's templates, then in the folder specified by the blueprint if not found.
## Example
# Create a blueprint with an independent template folder
bp = Blueprint("auth", __name__, template_folder="templates")
# Blueprint-specific template organization
# Path: auth/templates/auth/login.html
# When rendering: render_template("auth/login.html")
# This organization avoids filename conflicts (login.html might be different in auth and blog)
Recommended blueprint directory structure:
myflaskapp/βββ app.py # Application entry point, registers blueprintsβββ auth.py # Authentication blueprintβββ blog.py # Blog blueprintβββ templates/ # Application-level templates (public base.html, etc.)β βββ base.html βββ static/ # Application-level static filesβ βββ style.css βββ auth/ # auth blueprint's independent resources (optional)β βββ templates/β βββ auth/β βββ login.html β βββ register.html βββ blog/ # blog blueprint's independent resources (optional) βββ templates/ βββ blog/ βββ index.html βββ create.html
> The simplest approach is not to configure independent template folders for blueprints, but to place templates uniformly under the project root's templates/ directory, using subdirectories to distinguish them: templates/auth/login.html, templates/blog/index.html.
* * *
## Factory Patternβcreate_app
As blueprints multiply, creating app = Flask(__name__) directly at the module top level can cause circular import issues.
The Factory Pattern is the best practice to solve this problem:
## Example
# File path: app.py
from flask import Flask
def create_app():
"""Application factory functionβreturns a configured Flask instance"""
app = Flask( __name__ )
app.secret_key="dev-secret-key"
# Load configuration
app.config.from_pyfile("config.py", silent=True)
# Import blueprints inside the function to avoid circular references
from auth import bp as auth_bp
from blog import bp as blog_bp
# Register blueprints
app.register_blueprint(auth_bp, url_prefix="/auth")
app.register_blueprint(blog_bp)
return app
Advantages of the Factory Pattern:
* Eliminates Circular Imports: Blueprints can import app, and app can import blueprints, because imports happen inside the function
* Supports Testing: Can create app instances with different configurations for testing
* Multi-instance Deployment: The same code can create multiple independent app instances
After using the factory pattern, start the application via flask --app "app:create_app()" run:
$ flask --app "app:create_app()" run
* * *
## Other Functions in Blueprints
Blueprints also support decorators like before_request, errorhandler, etc., with usage identical to app:
## Example
@bp.before_request
def check_login():
"""Check login status before all requests in the auth blueprint"""
if request.endpoint not in("auth.login","auth.register"):
if"username"not in session:
return redirect(url_for("auth.login"))
@bp.errorhandler(404)
def not_found(error):
"""Auth blueprint-specific 404 error page"""
return render_template("auth/404.html"),404
> A blueprint's before_request only affects routes within that blueprint. If you need logic to execute before all requests, you should use app.before_request.
YouTip