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:

python
def create_app(config_name=None):
    app = Flask(__name__)
    app.config.from_object("config.DevelopmentConfig")
    register_blueprints(app)
    return app

Code 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:

python
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 in url_for("auth.login")
  • Routes use @auth_bp.route, not @app.route

Register Blueprints in Factory

app/__init__.py:

URLs:

EndpointURL
main.index/
auth.login/auth/login
auth.logout/auth/logout

Template link:

html
<a href="{{ url_for('auth.login') }}">Log in</a>

wsgi.py Entry Point

wsgi.py:

python
from app import create_app
 
app = create_app("production")

Gunicorn:

bash
gunicorn -w 4 'wsgi:app'

Or factory callable:

bash
gunicorn -w 4 'app:create_app()'

FLASK_APP for Development

bash
export FLASK_APP=app:create_app
export FLASK_DEBUG=1
flask run

Factory with config argument (optional pattern):

python
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:

python
# 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:

python
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.