Skip to main content

Flask Code Organization

When you start building Flask applications beyond simple "Hello World" examples, you'll quickly realize the importance of proper code organization. A well-structured Flask project improves maintainability, makes collaboration easier, and helps your application scale gracefully over time.

Why Code Organization Matters

As Flask follows the microframework philosophy, it doesn't enforce a specific project structure. This flexibility is both a blessing and a curse:

  • Advantage: You can adapt it to your specific needs
  • Challenge: Without proper organization, your application can quickly become a tangled mess

In this guide, we'll explore several approaches to organizing Flask applications, from simple to more complex architectures.

Basic Flask Application Structure

Let's start with a simple but well-organized Flask application structure:

my_flask_app/
├── app.py # Application entry point
├── config.py # Configuration settings
├── requirements.txt # Project dependencies
├── static/ # CSS, JS, images
│ ├── css/
│ ├── js/
│ └── images/
└── templates/ # HTML templates
├── base.html
└── index.html

Here's how a basic app.py might look:

python
from flask import Flask, render_template

app = Flask(__name__)

# Load configuration
app.config.from_object('config')

@app.route('/')
def index():
return render_template('index.html', title='Home')

if __name__ == '__main__':
app.run(debug=app.config['DEBUG'])

And a simple config.py:

python
# Configuration settings
DEBUG = True
SECRET_KEY = 'your-secret-key'

This structure works well for small applications with just a few routes, but it will become unwieldy as your application grows.

Scaling Up: Application Factory Pattern

As your application grows, you'll want to organize it better. The application factory pattern is a popular approach in Flask:

my_flask_app/
├── app/
│ ├── __init__.py # Application factory
│ ├── models/ # Database models
│ ├── routes/ # Route definitions
│ ├── static/ # Static files
│ └── templates/ # Templates
├── config.py # Configuration
├── requirements.txt # Dependencies
└── run.py # Application entry point

Here's how the application factory pattern works:

1. Application Factory (app/__init__.py):

python
from flask import Flask

def create_app(config_name='default'):
app = Flask(__name__)

# Load config
from config import config_dict
app.config.from_object(config_dict[config_name])

# Register blueprints
from app.routes.main import main_bp
app.register_blueprint(main_bp)

return app

2. Configuration (config.py):

python
class Config:
SECRET_KEY = 'base-secret-key'

class DevelopmentConfig(Config):
DEBUG = True

class ProductionConfig(Config):
DEBUG = False

config_dict = {
'development': DevelopmentConfig,
'production': ProductionConfig,
'default': DevelopmentConfig
}

3. Routes using Blueprints (app/routes/main.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')

@main_bp.route('/about')
def about():
return render_template('about.html', title='About')

4. Entry Point (run.py):

python
from app import create_app

app = create_app('development')

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

This approach has several advantages:

  • Separation of concerns
  • Easy testing (you can create different app instances with different configs)
  • Cleaner organization with blueprints for different sections of your app

Blueprints: Modular Applications

Blueprints are one of Flask's most powerful features for code organization. They allow you to divide your application into distinct components:

Example of Blueprint Structure:

my_flask_app/
├── app/
│ ├── __init__.py
│ ├── auth/ # Authentication blueprint
│ │ ├── __init__.py
│ │ ├── forms.py
│ │ ├── models.py
│ │ ├── routes.py
│ │ └── templates/
│ │ └── auth/
│ │ ├── login.html
│ │ └── register.html
│ ├── main/ # Main blueprint
│ │ ├── __init__.py
│ │ ├── routes.py
│ │ └── templates/
│ │ └── main/
│ │ ├── index.html
│ │ └── about.html
│ ├── static/
│ └── templates/
│ └── base.html
├── config.py
└── run.py

Here's how to implement a blueprint:

Auth Blueprint (app/auth/__init__.py):

python
from flask import Blueprint

auth_bp = Blueprint('auth', __name__, template_folder='templates')

from . import routes # Import routes at the end to avoid circular imports

Auth Routes (app/auth/routes.py):

python
from flask import render_template, redirect, url_for
from . import auth_bp

@auth_bp.route('/login')
def login():
return render_template('auth/login.html', title='Login')

@auth_bp.route('/register')
def register():
return render_template('auth/register.html', title='Register')

Register the Blueprint (app/__init__.py):

python
def create_app(config_name='default'):
app = Flask(__name__)

# Load config
from config import config_dict
app.config.from_object(config_dict[config_name])

# Register blueprints
from app.main import main_bp
from app.auth import auth_bp

app.register_blueprint(main_bp)
app.register_blueprint(auth_bp, url_prefix='/auth')

return app

Blueprints give you these benefits:

  • Modular code organization by feature or functionality
  • Isolated templates and static files
  • URL prefixing (like /auth/login in the example)
  • Easy to maintain and extend

Advanced: Feature-Based Structure

For larger applications, consider organizing by feature rather than by type:

my_flask_app/
├── app/
│ ├── __init__.py
│ ├── extensions.py # Flask extensions
│ ├── features/
│ │ ├── auth/ # Authentication feature
│ │ │ ├── __init__.py
│ │ │ ├── forms.py
│ │ │ ├── models.py
│ │ │ ├── routes.py
│ │ │ ├── static/
│ │ │ └── templates/
│ │ ├── blog/ # Blog feature
│ │ │ ├── __init__.py
│ │ │ ├── forms.py
│ │ │ ├── models.py
│ │ │ ├── routes.py
│ │ │ ├── static/
│ │ │ └── templates/
│ │ └── home/ # Home pages feature
│ │ ├── __init__.py
│ │ ├── routes.py
│ │ └── templates/
│ ├── static/ # Shared static files
│ └── templates/ # Shared templates
├── config.py
├── requirements.txt
└── run.py

This structure scales well for large applications with multiple developers, as each feature can be developed and maintained independently.

Real-World Example: A Blog Application

Let's put everything together with a more comprehensive example of a simple blog application:

Application Structure:

flask_blog/
├── app/
│ ├── __init__.py
│ ├── extensions.py
│ ├── models/
│ │ ├── __init__.py
│ │ ├── post.py
│ │ └── user.py
│ ├── auth/
│ │ ├── __init__.py
│ │ ├── forms.py
│ │ ├── routes.py
│ │ └── templates/
│ │ └── auth/
│ │ ├── login.html
│ │ └── register.html
│ ├── blog/
│ │ ├── __init__.py
│ │ ├── forms.py
│ │ ├── routes.py
│ │ └── templates/
│ │ └── blog/
│ │ ├── create.html
│ │ ├── edit.html
│ │ └── post.html
│ ├── main/
│ │ ├── __init__.py
│ │ ├── routes.py
│ │ └── templates/
│ │ └── main/
│ │ ├── index.html
│ │ └── about.html
│ ├── static/
│ └── templates/
│ └── base.html
├── config.py
├── requirements.txt
└── run.py

Extensions (app/extensions.py):

python
from flask_sqlalchemy import SQLAlchemy
from flask_login import LoginManager
from flask_migrate import Migrate

# Initialize extensions
db = SQLAlchemy()
login_manager = LoginManager()
migrate = Migrate()

def init_extensions(app):
# Initialize extensions with the app
db.init_app(app)
login_manager.init_app(app)
migrate.init_app(app, db)

login_manager.login_view = 'auth.login'

App Factory (app/__init__.py):

python
from flask import Flask

def create_app(config_name='default'):
app = Flask(__name__)

# Load config
from config import config_dict
app.config.from_object(config_dict[config_name])

# Initialize extensions
from app.extensions import init_extensions
init_extensions(app)

# Register blueprints
from app.main import main_bp
from app.auth import auth_bp
from app.blog import blog_bp

app.register_blueprint(main_bp)
app.register_blueprint(auth_bp, url_prefix='/auth')
app.register_blueprint(blog_bp, url_prefix='/blog')

return app

This structure provides a solid foundation for a Flask application that can scale as requirements grow.

Best Practices for Flask Code Organization

Regardless of the structure you choose, follow these best practices:

  1. Use Blueprints: Even for small applications, blueprints help organize code logically
  2. Separate Configuration: Keep configuration out of your application code
  3. Use Application Factory: Makes testing easier and avoids global state issues
  4. Keep Models Separate: Maintain clear separation between data models and views
  5. Don't Import Views at Module Level: Import views inside functions to avoid circular imports
  6. Follow Python Conventions: Use PEP 8 and consistent naming throughout your project
  7. Organize Templates: Structure templates to match your blueprint organization

Summary

Proper code organization is crucial for sustainable Flask application development. As your application grows, the right structure will help you maintain code quality and developer productivity.

Here's what we covered:

  • Basic Flask application structure
  • Application factory pattern
  • Using blueprints for modularity
  • Feature-based organization for larger applications
  • Real-world example of a blog application

Remember, there's no one-size-fits-all approach. Choose the structure that makes sense for your project's scale and complexity. Start simple and refactor as needed.

Additional Resources

Exercises

  1. Convert a simple Flask application to use the application factory pattern
  2. Restructure an existing project to use blueprints
  3. Create a Flask project with at least three blueprints: auth, main, and an API
  4. Implement a feature-based structure for a medium-sized Flask application
  5. Create a Flask extension and integrate it into your application


If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)