Flask Project Structure
When you start developing web applications with Flask, one of the first challenges you'll face is deciding how to structure your project. A well-organized Flask project is easier to maintain, scale, and collaborate on. In this guide, we'll explore different approaches to structuring Flask applications, from simple single-file apps to more complex, modular structures.
Why Project Structure Matters
Having a good project structure provides several benefits:
- Maintainability: Easier to read, understand, and update code
- Scalability: Ability to grow your application without major refactoring
- Collaboration: Allows teams to work on different parts of the application simultaneously
- Testing: Makes it easier to write and run tests
- Reusability: Encourages modular code that can be reused across projects
Simple Flask Application Structure
For beginners or very small applications, a single-file approach works fine:
# app.py
from flask import Flask, render_template
app = Flask(__name__)
@app.route('/')
def home():
return render_template('index.html')
@app.route('/about')
def about():
return render_template('about.html')
if __name__ == '__main__':
app.run(debug=True)
With templates in a simple folder structure:
project/
├── app.py
├── static/
│ ├── css/
│ │ └── style.css
│ └── js/
│ └── script.js
└── templates/
├── index.html
└── about.html
This works for simple applications, but as your project grows, you'll need a more structured approach.
Basic Package Structure
As your application grows, you should move to a package structure. This separates concerns and makes your code more modular:
myapp/
├── __init__.py
├── routes.py
├── models.py
├── forms.py
├── static/
│ ├── css/
│ └── js/
└── templates/
Let's see how these files would work together:
# __init__.py
from flask import Flask
app = Flask(__name__)
app.config['SECRET_KEY'] = 'your-secret-key'
from myapp import routes
# routes.py
from flask import render_template
from myapp import app
@app.route('/')
def home():
return render_template('index.html')
@app.route('/about')
def about():
return render_template('about.html')
To run this application, you'd create a run.py
file in the parent directory:
# run.py
from myapp import app
if __name__ == '__main__':
app.run(debug=True)
Advanced Modular Structure
For larger applications, you'll want to use a modular structure with blueprints. Blueprints allow you to organize related functionality into separate components:
myapp/
├── __init__.py
├── config.py
├── extensions.py
├── models/
│ ├── __init__.py
│ ├── user.py
│ └── post.py
├── modules/
│ ├── __init__.py
│ ├── main/
│ │ ├── __init__.py
│ │ ├── routes.py
│ │ └── forms.py
│ ├── auth/
│ │ ├── __init__.py
│ │ ├── routes.py
│ │ └── forms.py
│ └── blog/
│ ├── __init__.py
│ ├── routes.py
│ └── forms.py
├── static/
├── templates/
│ ├── main/
│ ├── auth/
│ └── blog/
└── utils/
├── __init__.py
└── helpers.py
Here's how these files would work together:
# config.py
class Config:
SECRET_KEY = 'your-secret-key'
SQLALCHEMY_DATABASE_URI = 'sqlite:///site.db'
SQLALCHEMY_TRACK_MODIFICATIONS = False
class DevelopmentConfig(Config):
DEBUG = True
class ProductionConfig(Config):
DEBUG = False
config = {
'development': DevelopmentConfig,
'production': ProductionConfig,
'default': DevelopmentConfig
}
# extensions.py
from flask_sqlalchemy import SQLAlchemy
from flask_login import LoginManager
db = SQLAlchemy()
login_manager = LoginManager()
# __init__.py
from flask import Flask
from myapp.config import config
from myapp.extensions import db, login_manager
def create_app(config_name='default'):
app = Flask(__name__)
app.config.from_object(config[config_name])
# Initialize extensions
db.init_app(app)
login_manager.init_app(app)
# Register blueprints
from myapp.modules.main import main_bp
from myapp.modules.auth import auth_bp
from myapp.modules.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
Let's create a blueprint for the main module:
# modules/main/__init__.py
from flask import Blueprint
main_bp = Blueprint('main', __name__)
from . import routes
# modules/main/routes.py
from flask import render_template
from myapp.modules.main import main_bp
@main_bp.route('/')
def home():
return render_template('main/index.html')
@main_bp.route('/about')
def about():
return render_template('main/about.html')
To run this application, you'd create a run.py
file:
# run.py
from myapp import create_app
app = create_app('development')
if __name__ == '__main__':
app.run()
Project Structure for Production
For production applications, you might want to include additional files and folders:
myapp/
├── migrations/ # For database migrations using Flask-Migrate
├── tests/ # For unit tests
│ ├── __init__.py
│ ├── test_models.py
│ └── test_routes.py
├── .env # For environment variables (keep this out of version control!)
├── .gitignore
├── requirements.txt # For project dependencies
└── wsgi.py # Entry point for WSGI servers like Gunicorn
The wsgi.py
file would be simple:
# wsgi.py
from myapp import create_app
app = create_app('production')
Real-World Example: Flask Blog Application
Let's see how we might structure a simple blog application:
flask_blog/
├── __init__.py
├── config.py
├── extensions.py
├── models/
│ ├── __init__.py
│ ├── user.py
│ └── post.py
├── blueprints/
│ ├── __init__.py
│ ├── main/
│ │ ├── __init__.py
│ │ └── routes.py
│ ├── auth/
│ │ ├── __init__.py
│ │ ├── routes.py
│ │ └── forms.py
│ └── blog/
│ ├── __init__.py
│ ├── routes.py
│ └── forms.py
├── static/
│ ├── css/
│ │ └── style.css
│ ├── js/
│ │ └── script.js
│ └── images/
├── templates/
│ ├── base.html
│ ├── main/
│ │ ├── index.html
│ │ └── about.html
│ ├── auth/
│ │ ├── login.html
│ │ └── register.html
│ └── blog/
│ ├── create_post.html
│ ├── edit_post.html
│ └── post_detail.html
├── requirements.txt
└── run.py
Here's part of our blog post model:
# models/post.py
from datetime import datetime
from flask_blog.extensions import db
class Post(db.Model):
id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.String(100), nullable=False)
content = db.Column(db.Text, nullable=False)
date_posted = db.Column(db.DateTime, nullable=False, default=datetime.utcnow)
user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
def __repr__(self):
return f"Post('{self.title}', '{self.date_posted}')"
And part of our blog routes:
# blueprints/blog/routes.py
from flask import render_template, redirect, url_for, flash, request, abort
from flask_login import current_user, login_required
from flask_blog.models.post import Post
from flask_blog.extensions import db
from flask_blog.blueprints.blog import blog_bp
from flask_blog.blueprints.blog.forms import PostForm
@blog_bp.route('/post/new', methods=['GET', 'POST'])
@login_required
def new_post():
form = PostForm()
if form.validate_on_submit():
post = Post(title=form.title.data, content=form.content.data, author=current_user)
db.session.add(post)
db.session.commit()
flash('Your post has been created!', 'success')
return redirect(url_for('blog.post', post_id=post.id))
return render_template('blog/create_post.html', title='New Post', form=form)
Best Practices For Flask Project Structure
-
Separate Configuration: Keep configuration separate from application code, and use different configurations for development, testing, and production.
-
Use Application Factory Pattern: Create your Flask application with a function, allowing for easy testing and multiple instances.
-
Organize by Feature: Group related functionality together (e.g., models, views, templates) rather than by type.
-
Use Blueprints: Break your application into logical components with Flask blueprints.
-
Keep Requirements Updated: Maintain a
requirements.txt
file and consider usingpip-tools
orpoetry
for dependency management. -
Environment Variables: Use
.env
files andpython-dotenv
to manage environment-specific variables. -
Include Tests: Always include tests in your project structure.
Common Pitfalls to Avoid
- Circular Imports: Structure your application to avoid circular imports, which can cause difficult-to-debug errors.
- Monolithic Files: Don't put too much code in a single file; break things down logically.
- Hardcoded Configuration: Avoid hardcoding configuration values; use environment variables or configuration files.
- Ignoring Tests: Don't leave testing as an afterthought; include it in your structure from the beginning.
Summary
A well-structured Flask application makes development easier, more maintainable, and more scalable. As your application grows, your structure should evolve from a simple single-file approach to a more modular structure using packages and blueprints.
Remember that the "best" structure depends on your specific project requirements. Flask's flexibility allows you to adapt your structure as needed, but having a solid foundation from the beginning will save you time and headaches later.
Additional Resources
- Flask Documentation on Application Structure
- Flask Mega-Tutorial by Miguel Grinberg
- Awesome Flask Repository
- Flask Project Structure Examples on GitHub
Exercises
- Convert a simple single-file Flask application to a package structure.
- Create a Flask application with two blueprints: "main" and "admin".
- Implement a Flask project structure that includes models, forms, and templates for a simple to-do list application.
- Set up different configuration classes for development and production environments.
- Implement a Flask application factory pattern in your project.
If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)