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:
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
:
# 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
):
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
):
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
):
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
):
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
):
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
):
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
):
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
):
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
):
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:
- Use Blueprints: Even for small applications, blueprints help organize code logically
- Separate Configuration: Keep configuration out of your application code
- Use Application Factory: Makes testing easier and avoids global state issues
- Keep Models Separate: Maintain clear separation between data models and views
- Don't Import Views at Module Level: Import views inside functions to avoid circular imports
- Follow Python Conventions: Use PEP 8 and consistent naming throughout your project
- 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
- Flask's Official Documentation on Application Structure
- Miguel Grinberg's Flask Mega-Tutorial
- Flask Project Structure on Explore Flask
Exercises
- Convert a simple Flask application to use the application factory pattern
- Restructure an existing project to use blueprints
- Create a Flask project with at least three blueprints: auth, main, and an API
- Implement a feature-based structure for a medium-sized Flask application
- 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! :)