Flask is a microframework and it does not restrict us with a single pattern of the folder structure. Instead, it gives us the freedom to implement our own choice of solution. Just like everything has 2 sides good and bad, the same concept applies here as well. Yes, we can build our own flask project structure but you will find various different implementations all over the internet. So after some research and implementation, I come up with the entry-level project structure for a flask application.

Flask Project Structure

The reason I called it entry level is because I am not going to add custom commands or something like that to complicate the main objective.

Our main objective is to define a flask project structure that is highly scalable.

I have myself worked on various back-end frameworks including Laravel, Django, CodeIgniter, etc.

All of these frameworks have a different architecture that they follow. Now let's first understand why people think about the scalability of a web application.

As it’s a Flask-based article so let’s discuss it in the Flask way. You start building a web application with a very basic idea and with time it keeps growing.

You are adding more code into the same python file and suddenly you see it's getting buffed up and you are having serious issues debugging.

You can imagine 100s of methods in a single python file. So in order to get rid of this issue Blueprint was introduced.

Flask Blueprint

Blueprint provides a very clean way to build a modular domain-driven flask project structure. If you have used Django then you will find it very similar.

Reasons to use blueprints

There are various reasons to use blueprints in Flask.

  • Blueprints can help to split the entire codebase into smaller blocks
  • It can help us to design a domain-driven flask project structure
  • Increases code re-usability
  • Blueprints can have their own set of static files, templates, and custom error pages as well.

So let’s quickly set up a flask project with blueprints.


flask project structure blueprints

We are going to use the above structure for our application. Let's start from the top and understand the utility of each file.

The basic concept here is one flask website can have multiple apps and each app will have its own set of models, views, and templates.

Here apps are flask blueprints so you name the folder apps or blueprints.

app.py

from flask import Flask
from database import database

# blueprint import
from apps.app1.views import app1
from apps.app2.views import app2

def create_app():
    app = Flask(__name__)
    # setup with the configuration provided
    app.config.from_object('config.DevelopmentConfig')
    
    # setup all our dependencies
    database.init_app(app)
    
    # register blueprint
    app.register_blueprint(app1)
    app.register_blueprint(app2, url_prefix="/app2")
    
    return app

if __name__ == "__main__":
    create_app().run()

Here inside the app.py, we have imported the blueprints from the app's directory. We have a single method that sets up our flask application with config data from the config.py file.

Also, it calls the init_app method of SQLAlchemy to setup it with our flask application and creates all the databases.

Next, we register the blueprints with the register_blueprint method. Where we can also additionally pass url_prefix.

Finally in the if block we will call the run method on our app.

config.py

import os

class Config(object):
    DEBUG = False
    TESTING = False
    CSRF_ENABLED = True
    SECRET_KEY = '57e19ea558d4967a552d03deece34a70'
    SQLALCHEMY_TRACK_MODIFICATIONS = False

class ProductionConfig(Config):
    DEBUG = False
    SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URL')

class DevelopmentConfig(Config):
    ENV="development"
    DEVELOPMENT=True
    DEBUG=True
SQLALCHEMY_DATABASE_URI="sqlite:///development_database.db"

The config.py has a class called config and then we have 2 inherited classes. The ProductionConfig class contains the configuration values for production.

The DevelopmentConfig class contains configuration for development.

database.py

from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()

def init_app(app):
    db.init_app(app)
    db.create_all(app=app)

This file will just create an SQLAlchemy object and initialize it and create all the database tables from all the models.py files inside blueprints or apps.

static folder

The static folder at the root level will contain all the static files required in the entire project. We can also have individual static folders for each blueprint.

However in that case using url_prefix is compulsory. So it's better to have a single static folder placed at the root.

templates folder

The templates folder at the root will contain all the layout files which will be accessible to all the blueprints.

As the layout files are going to access from blueprints as well so it's better to put them at the root level.

apps folder

The apps folder of our flask project structure contains all the blueprints and we can have as many as blueprints inside it like auth, blog, store, etc.

blueprint folder (app1, app2)

The most important part of our flask project structure.

Each blueprint will have a views.py, models.py file, and templates folder. Inside the templates, the folder makes sure to create another folder with the name of the blueprint folder.

You can have 2 templates with the same file name inside 2 different blueprints. In that case, the flask will use the first one it found.

In order to get rid of this ambiguous situation, it's necessary to create a folder with a blueprint name inside templates.

apps/app1/views.py

from flask import Blueprint, request, url_for, redirect, render_template, flash
app1 = Blueprint('app1', __name__, template_folder="templates/app1")

@app1.route("/")
def home():
    return render_template('index.html')

@app1.app_errorhandler(404)
def page_not_found(e):
    return render_template('404.html'), 404

Just import Blueprint from the flask and add a single line to convert a views file into a blueprint.

Inside the blueprint constructor, we have passed the name and template folder path. Additionally, static files path can be passed as well.

Each blueprint can have its own error handler as well. Which we can create by using app_errorhandler.

apps/app1/models.py

from database.database import db
from flask_login import UserMixin

class User(db.Model, UserMixin):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(150))
    email = db.Column(db.String(150), unique=True)
    password = db.Column(db.String(150))

def __init__(self, name, email):
    self.name = name
    self.email = email

In the models file of blueprints, we can simply import db and create models with SQLAlchemy.

apps/app1/templates/app1/index.html

{% extends "layouts/app.html" %}

{% block content %}
<div class="container">
    <h1 class="text-muted text-center">Build an amazing Flask App</h1>
</div>
{% endblock %}

The templates inside blueprints can easily extend the layouts. Here the layouts/app.html will take the file content from the root.

So this is the way to use blueprints with a flask to create a flask project structure that helps to scale.

You can also have a folder called extensions at the root level to handle the initialization and setup of different flask extensions.

I hope this article has helped you to setup a flask project structure. It's suitable to use when you’re working on a mid-level or large scale application.

Otherwise, it will unnecessarily create an overhead. Feel free to share your thoughts below.