Flask Blueprints for Scalable Web Applications

Dynamic Flask Application Configuration

When developing a Flask appplication in a single file, the Flask object app is created in the global scope. This meens any configuration changes after the script runs won’t take effect. To resolve this, move app creation to a explicitly callable factory function, delaying instance initialization.

Factory function: app/init.py

from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_wtf.csrf import CSRFProtect
from config import config_options

# Initialize extensions without app context
db = SQLAlchemy()
csrf_protection = CSRFProtect()

def create_app(env_name):
    app = Flask(__name__)
    app.config.from_object(config_options[env_name])
    config_options[env_name].init_app(app)

    # Register extensions
    db.init_app(app)
    csrf_protection.init_app(app)

    return app

Call create_app() with a dynamic environment name to apply the correct configuration.

Implementing Blueprints

The factory function solves dynamic configuration, but routing becomes an issue. In single-file apps, @app.route decorators directly attach routes to the global app instance. With delayed app creation, routes can’t be defined until create_app() is called. Flask blueprints address this by allowing routes to be defined independently of the app instance and registered later.

Blueprint definition: app/main/init.py

from flask import Blueprint

# Create blueprint with name and module context
main_bp = Blueprint('main', __name__)

# Import views to register routes with the blueprint
from . import views

Registering blueprints in app/init.py

from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_wtf.csrf import CSRFProtect
from config import config_options

db = SQLAlchemy()
csrf_protection = CSRFProtect()

def create_app(env_name):
    app = Flask(__name__)
    app.config.from_object(config_options[env_name])
    config_options[env_name].init_app(app)

    db.init_app(app)
    csrf_protection.init_app(app)

    # Register blueprints
    from .main import main_bp
    from .auth import auth_bp
    app.register_blueprint(main_bp)
    app.register_blueprint(auth_bp, url_prefix='/auth')

    return app

Blueprint routes: app/main/views.py

from datetime import datetime
from flask import render_template, session, redirect, url_for
from . import main_bp

@main_bp.route('/dashboard', methods=['GET', 'POST'])
def dashboard():
    return render_template('dashboard.html')

Application Startup Script

Use Flask-Script and Flask-Migrate for command-line management. Create manage.py to handle app initialization and database migrations.

manage.py

import os
from flask_script import Manager, Shell
from flask_migrate import Migrate, MigrateCommand
from app import create_app
from app import db

# Initialize app with environment variable or default to development
app = create_app(os.getenv('FLASK_ENV') or 'dev')
manager = Manager(app)
migrate = Migrate(app, db)

# Shell context for interactive debugging
def make_shell_context():
    return {'app': app, 'db': db}

manager.add_command('shell', Shell(make_context=make_shell_context))
manager.add_command('db', MigrateCommand)

if __name__ == '__main__':
    manager.run()

Install Flask-Script and Flask-Migrate first, then run python manage.py to start the application.

Complete Project Structure

|-- flask_project
    |-- config.py
    |-- environment.yml
    |-- manage.py
    |-- app
    |   |-- models.py
    |   |-- __init__.py
    |   |-- auth
    |   |   |-- forms.py
    |   |   |-- views.py
    |   |   |-- __init__.py
    |   |   |-- templates
    |   |-- main
    |   |   |-- errors.py
    |   |   |-- forms.py
    |   |   |-- views.py
    |   |   |-- __init__.py
    |   |-- static
    |   |   |-- css
    |   |   |-- img
    |   |   |-- js
    |   |-- templates
    |-- migrations
    |-- tests
    |   |-- __init__.py
    |-- venv

Dynamic Configuration Classes

Define environment-specific configuration classes in config.py.

config.py

import os
basedir = os.path.abspath(os.path.dirname(__file__))

class BaseConfig:
    CSRF_SECRET = os.environ.get('CSRF_SECRET') or 'secure-csrf-token'
    SECRET_KEY = os.environ.get('SECRET_KEY') or 'secure-session-key'
    SQLALCHEMY_COMMIT_ON_TEARDOWN = True
    SQLALCHEMY_TRACK_MODIFICATIONS = False

    @staticmethod
    def init_app(app):
        app.config['SECRET_KEY'] = BaseConfig.SECRET_KEY
        app.config['CSRF_SECRET'] = BaseConfig.CSRF_SECRET
        app.config['SQLALCHEMY_COMMIT_ON_TEARDOWN'] = BaseConfig.SQLALCHEMY_COMMIT_ON_TEARDOWN
        app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = BaseConfig.SQLALCHEMY_TRACK_MODIFICATIONS

class DevelopmentConfig(BaseConfig):
    DEBUG = True
    SQLALCHEMY_DATABASE_URI = os.environ.get('DEV_DB_URL') or \
                              'sqlite:///' + os.path.join(basedir, 'dev-db.sqlite')

class TestingConfig(BaseConfig):
    TESTING = True
    SQLALCHEMY_DATABASE_URI = os.environ.get('TEST_DB_URL') or \
                              'sqlite:///' + os.path.join(basedir, 'test-db.sqlite')

class ProductionConfig(BaseConfig):
    SQLALCHEMY_DATABASE_URI = os.environ.get('PROD_DB_URL') or \
                              'sqlite:///' + os.path.join(basedir, 'prod-db.sqlite')

config_options = {
    'dev': DevelopmentConfig,
    'test': TestingConfig,
    'prod': ProductionConfig,
    'default': DevelopmentConfig
}

Tags: Flask Blueprint python web development Flask-Script

Posted on Sun, 31 May 2026 22:32:41 +0000 by Garcia