Flask Application Factory Pattern: Benefits, Example, and Pitfalls
Learn how the Flask application factory pattern creates configurable, testable apps, see a full create_app example, and avoid common context and import mistakes.
05 Aug 2026, 23:15 UTC

Use the Flask application factory to create configurable apps
Start by defining a create_app() function that returns a configured Flask instance. This lets you create separate apps for development, testing, and production without global state.
Worked example
# project/__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_object='project.config.DevelopmentConfig'):
app = Flask(__name__)
app.config.from_object(config_object)
# Initialize extensions
db.init_app(app)
login_manager.init_app(app)
login_manager.login_view = 'auth.login'
# Register blueprints
from project.auth import auth as auth_blueprint
app.register_blueprint(auth_blueprint)
from project.main import main as main_blueprint
app.register_blueprint(main_blueprint)
# Shell context for flask shell
@app.shell_context_processor
def make_shell_context():
return {'db': db, 'app': app}
return app
Place the factory in project/__init__.py so that flask run can discover it by setting the environment variable:
export FLASK_APP=projectexport FLASK_ENV=developmentflask run
When the factory is called, Flask loads the configuration object, binds extensions via init_app(), and registers blueprints. Because the db and login_manager objects are created outside the factory, they are not tied to a specific app until init_app() runs inside create_app().
Limits and common mistakes
- Missing application context: accessing
current_apporgoutside a view or without pushingapp.app_context()raisesRuntimeError: Working outside of application context. Fix by wrapping code inwith app.app_context():or usingflask shellwhich pushes a context automatically. - Setting configuration after extension initialization: if you load config after calling
db.init_app(app), the extension may use default values (e.g.,SQLALCHEMY_DATABASE_URI) leading to connection errors. Load config before anyinit_app()calls. - Circular imports: importing views or models that reference the app inside
create_app()before the app is fully constructed can cause import loops. Keep those imports inside the function or use lazy loading (e.g.,from . import modelsafterdb.init_app(app)). - Extension state leakage: because extensions are initialized with
init_app(), they should not retain state between app instances. Verify by creating two apps with different configs and checking thatapp.config['SQLALCHEMY_DATABASE_URI']differs.
Practical verification
- Run the factory:
export FLASK_APP=project && flask run. The server should start without errors and serve the routes defined in the blueprints. - Check isolation: in a Python shell,
from project import create_app; a1 = create_app('project.config.DevelopmentConfig'); a2 = create_app('project.config.TestingConfig'); print(a1.config['SECRET_KEY'] != a2.config['SECRET_KEY'])should outputTrue. - Test context:
with a1.app_context(): from flask import current_app; print(current_app.name)prints the app name, confirming the context is active.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.