Flask Factory Pattern Project Structure
Application factory with config classes and CLI. Production-ready Flask architecture.
Project Directory
myproject/
wsgi.py
WSGI entry point (Gunicorn)
manage.py
CLI commands (optional)
requirements.txt
requirements/
Split by environment
base.txt
dev.txt
prod.txt
.env
.env.example
.gitignore
config/
Configuration classes
__init__.py
Config selector
base.py
Shared settings
development.py
production.py
testing.py
app/
Application package
__init__.py
create_app() factory
extensions.py
db, migrate, login, etc.
cli.py
Custom Flask CLI commands
models/
Split models by domain
__init__.py
Model imports
user.py
post.py
views/
All blueprints
__init__.py
main.py
Main blueprint
auth.py
Auth blueprint
api.py
API blueprint
services/
Business logic
__init__.py
user_service.py
email_service.py
templates/
base.html
main/
auth/
errors/
404.html, 500.html
static/
css/
js/
images/
utils/
Helper functions
__init__.py
decorators.py
helpers.py
tests/
__init__.py
conftest.py
App fixture with test config
test_models.py
test_views.py
test_services.py
migrations/
Flask-Migrate (Alembic)
versions/
env.py
alembic.ini
Why This Structure?
The factory pattern is Flask best practice for production. create_app() initializes everything based on config classes. This enables different configs for dev/test/prod, proper testing with isolated app instances, and clean separation between configuration and application code.
Key Directories
- config/-Environment-specific config classes (Development, Production, Testing)
- app/__init__.py-create_app(config_name) factory function
- app/services/-Business logic separate from routes
- app/views/-Blueprints organized as single files
- tests/conftest.py-Pytest fixtures with test app instance
Application Factory
# app/__init__.py
def create_app(config_name='development'):
app = Flask(__name__)
app.config.from_object(config[config_name])
# Initialize extensions
db.init_app(app)
migrate.init_app(app, db)
login_manager.init_app(app)
# Register blueprints
from app.views import main_bp, auth_bp, api_bp
app.register_blueprint(main_bp)
app.register_blueprint(auth_bp, url_prefix='/auth')
app.register_blueprint(api_bp, url_prefix='/api')
return app
Config Classes
# config/base.py
class BaseConfig:
SECRET_KEY = os.environ.get('SECRET_KEY')
SQLALCHEMY_TRACK_MODIFICATIONS = False
# config/development.py
class DevelopmentConfig(BaseConfig):
DEBUG = True
SQLALCHEMY_DATABASE_URI = 'sqlite:///dev.db'
# config/production.py
class ProductionConfig(BaseConfig):
SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URL')
Getting Started
python -m venv venv && source venv/bin/activatepip install -r requirements/dev.txtcp .env.example .env && edit .envexport FLASK_APP=wsgi.py FLASK_ENV=developmentflask db upgradeflask run
When To Use This
- Production deployments
- Need different configs for dev/staging/prod
- Business logic complex enough for service layer
- Team of 3+ developers
- Projects needing comprehensive test coverage
Testing Setup
# tests/conftest.py
@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()
Trade-offs
- More structure-Overkill for small projects
- Initial setup-Takes time to scaffold properly
- Import complexity-Must understand factory initialization order