Flask Application Factory
The Application Factory pattern moves app creation into a function. Instead of creating the Flask app at the module level, a function called create_app() builds and returns it. This pattern supports multiple configurations (testing, development, production) and fixes circular import problems in larger projects.
The Problem with Module-Level App Creation
In a small app, this works fine:
app = Flask(__name__) # module-level creationIn a larger app with blueprints and extensions, every module imports app from this file. If those modules also define models or routes that app.py imports, Python hits a circular import — Module A imports Module B which imports Module A, creating an infinite loop.
The Factory Function Solution
# app/__init__.py
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_login import LoginManager
db = SQLAlchemy()
login_manager = LoginManager()
def create_app(config_name='default'):
app = Flask(__name__)
# Load config
from app.config import config
app.config.from_object(config[config_name])
# Initialize extensions
db.init_app(app)
login_manager.init_app(app)
# Register blueprints
from app.auth import auth as auth_bp
from app.blog import blog as blog_bp
app.register_blueprint(auth_bp, url_prefix='/auth')
app.register_blueprint(blog_bp, url_prefix='/blog')
return app
How Extensions Work with the Factory
Extensions like SQLAlchemy and LoginManager are created without an app object (db = SQLAlchemy()). Later, db.init_app(app) binds them to the specific app instance. This separation allows the same extension objects to be imported anywhere without a circular dependency.
Without Factory: app = Flask() db = SQLAlchemy(app) ← db tied to one specific app With Factory: db = SQLAlchemy() ← db created standalone db.init_app(app) ← bound at runtime inside create_app()
Configuration Classes
Create a config.py file with separate classes for each environment:
import os
class Config:
SECRET_KEY = os.environ.get('SECRET_KEY') or 'dev-secret'
SQLALCHEMY_TRACK_MODIFICATIONS = False
class DevelopmentConfig(Config):
DEBUG = True
SQLALCHEMY_DATABASE_URI = 'sqlite:///dev.db'
class TestingConfig(Config):
TESTING = True
SQLALCHEMY_DATABASE_URI = 'sqlite:///:memory:'
class ProductionConfig(Config):
DEBUG = False
SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URL')
config = {
'development': DevelopmentConfig,
'testing': TestingConfig,
'production': ProductionConfig,
'default': DevelopmentConfig
}The Entry Point
Create a run.py (or wsgi.py) file at the project root:
import os
from app import create_app
app = create_app(os.environ.get('FLASK_ENV', 'development'))
if __name__ == '__main__':
app.run()Complete Project Structure with Factory
myapp/
├── run.py ← entry point
├── config.py ← environment configs
├── requirements.txt
└── app/
├── __init__.py ← create_app() lives here
├── models.py ← SQLAlchemy models
├── auth/
│ ├── __init__.py
│ └── routes.py
├── blog/
│ ├── __init__.py
│ └── routes.py
├── templates/
└── static/
Testing with the Factory
The factory makes testing simple — create a fresh app instance with the test configuration for each test suite:
import pytest
from app import create_app, db
@pytest.fixture
def app():
app = create_app('testing')
with app.app_context():
db.create_all()
yield app
db.drop_all()
@pytest.fixture
def client(app):
return app.test_client()Each test gets an isolated in-memory database. Tests cannot affect each other's data.
Summary
The Application Factory pattern wraps Flask app creation in a create_app() function. Extensions are initialized separately and bound with .init_app(app). Different config classes handle development, testing, and production environments. Blueprints register inside the factory. This pattern eliminates circular imports, enables parallel test environments, and gives you full control over how each instance of your app is configured.
