Blueprints and Application Factory
Introduction
A single app.py file stops scaling once routes, forms, and models multiply. Blueprints group related routes into modules; the application factory builds a configured Flask instance for production, tests, and CLI tools. This pattern is the standard layout for real Flask projects.
Prerequisites
Why an Application Factory?
Problems with global app = Flask(__name__) at import time:
- Tests cannot easily use different configs
- Circular imports when models import
app - Celery/CLI need multiple app instances
Solution:
def create_app(config_name=None):
app = Flask(__name__)
app.config.from_object("config.DevelopmentConfig")
register_blueprints(app)
return appCode explanation:
create_app()runs at startup (Gunicorn, tests,flask run) with the right config- Nothing creates the app at import except the factory call site
Project Layout
config.py
Create Blueprint
app/auth/routes.py:
app/main/routes.py:
from flask import Blueprint, render_template
main_bp = Blueprint("main", __name__)
@main_bp.route("/")
def index():
return render_template("index.html", title="Home")Code explanation:
Blueprint("auth", __name__)first argument is the blueprint name used inurl_for("auth.login")- Routes use
@auth_bp.route, not@app.route
Register Blueprints in Factory
app/__init__.py:
URLs:
| Endpoint | URL |
|---|---|
main.index | / |
auth.login | /auth/login |
auth.logout | /auth/logout |
Template link:
<a href="{{ url_for('auth.login') }}">Log in</a>wsgi.py Entry Point
wsgi.py:
from app import create_app
app = create_app("production")Gunicorn:
gunicorn -w 4 'wsgi:app'Or factory callable:
gunicorn -w 4 'app:create_app()'FLASK_APP for Development
export FLASK_APP=app:create_app
export FLASK_DEBUG=1
flask runFactory with config argument (optional pattern):
def create_app(config_name="development"):
...Pass via custom CLI or env FLASK_CONFIG=testing in your project.
Avoid Circular Imports
Import blueprints inside create_app, not at module top of __init__.py before app exists.
Models that need db:
# extensions.py
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
# __init__.py inside create_app
from app.extensions import db
db.init_app(app)Import models after db.init_app in factory or use app.app_context() in CLI.
Testing With Factory
Full testing chapter expands fixtures and database setup.
Tip
One Blueprint Per Feature
Split auth, blog, api—keeps files small and teams can work in parallel.
FAQ
url_for BuildError auth.login?
Blueprint not registered or wrong endpoint name—use auth.login when blueprint name is auth.
Templates not found after move?
Set template_folder on blueprint or keep shared templates/ at app root:
auth_bp = Blueprint("auth", __name__, template_folder="templates")Static files per blueprint?
static_folder="static" on blueprint—URLs include blueprint name prefix.
create_app called twice?
Use @app.cli.command or single wsgi.py entry—idempotent factory is fine.
Circular import on models?
Use extensions.py pattern; import models inside routes or after app context.
Same route in two blueprints?
Allowed with different prefixes—endpoint names must stay unique across the app.