Building a Monolith App with Flask
I had several small Flask apps costing me each month, so I consolidated them into one monolithic app using Flask Blueprints. This post walks you through how I did it, making the setup modular and easy to maintain.
I had been meaning to do this for some time. I had a bunch of random Flask apps running on DigitalOcean, each costing me $6 a month. These were small hacks and experiments with APIs and tools, not ready for prime time.
I decided to bring them all together into a single monolithic app using Flask and Blueprints. This setup allows me to quickly add new services without setting up new apps each time. Plus, it saves me money and keeps everything organized.
If you’re interested, I created a starter kit to show how to implement multiple services using Blueprints. You can check it out on GitHub.
Flask was the obvious choice since all my apps were already Flask apps. Initially, I thought I’d just add all the services with multiple routes in a single app.py file. But then, I decided to make it modular. Easier to maintain that way using Blueprints.
Enter Python Blueprints
Blueprints let you organize your Flask app into smaller, reusable components. Each service can have its own routes, templates, and static files. This keeps the app organized and maintainable.
I wasn’t familiar with Blueprints at first, but a little bit of research convinced me they were the way to go for my monolith.
Here's a step-by-step process on how I did it. For simplicity, I am using fictitious services SuperApp and DuperApp to explain a simple "hello world" sort of monolith app. This will hopefully help you get started with it, and then you can go from there to add other bells and whistles.
Step-by-Step Guide to Setting Up Blueprints
1. Creating Directories
First, set up the directory structure for your Flask app. You'll need to create several directories: services
for your service logic, templates
for HTML templates, and static
for static files like images and CSS.
Here’s how it should look:
/flask_monolith
|____app.py # Main application script where the Flask app is defined and run.
|____config.py # Contains configuration settings such as secret keys.
|____requirements.txt # Lists all project dependencies for pip installation.
|____static # Directory for static files like CSS, JS, and images.
| |____images
| | |____logo.png
|____templates # Jinja2 templates directory.
| |____home.html # Template for the home page.
| |____base.html # Base template that other templates extend.
| |____superapp # Templates specific to the SuperApp service.
| | |____index.html
| |____duperapp # Templates specific to the DuperApp service.
| | |____index.html
|____services # Python code for services.
| |____superapp
| | |______init__.py # Initializes superapp as a package.
| | |____superapp.py # Contains logic and routes for superapp.
| |____duperapp
| | |______init__.py # Initializes duperapp as a package.
| | |____duperapp.py # Contains logic and routes for duperapp.
2. Creating a Service File for Each Service
Inside the services
directory, create a subdirectory for each service. Each service should have an __init__.py
file and a service file (superapp.py
, duperapp.py
, etc.).
For SuperApp:
services/superapp/__init__.py
:
from flask import Blueprint
superapp_bp = Blueprint('superapp', __name__, template_folder='templates')
from . import superapp
services/superapp/superapp.py
:
from flask import render_template
from . import superapp_bp
@superapp_bp.route('/')
def index():
return render_template('superapp/index.html')
For DuperApp:
services/duperapp/__init__.py
:
from flask import Blueprint
duperapp_bp = Blueprint('duperapp', __name__, template_folder='templates')
from . import duperapp
services/duperapp/duperapp.py
:
from flask import render_template
from . import duperapp_bp
@duperapp_bp.route('/')
def index():
return render_template('duperapp/index.html')
3. Setting Up Templates
Templates for each service should be placed in their respective subdirectories within the templates
directory. This keeps the templates modular and easier to manage.
For example:
- Templates for
superapp
are intemplates/superapp/
- Templates for
duperapp
are intemplates/duperapp/
4. Registering Blueprints in app.py
In the main application file (app.py
), register these blueprints:
from flask import Flask, render_template
from services.superapp import superapp_bp
from services.duperapp import duperapp_bp
def create_app():
app = Flask(__name__)
app.config['SECRET_KEY'] = 'your-secret-key'
# Register Blueprints
app.register_blueprint(superapp_bp, url_prefix='/superapp')
app.register_blueprint(duperapp_bp, url_prefix='/duperapp')
@app.route('/')
def home():
return render_template('home.html')
return app
if __name__ == '__main__':
app = create_app()
app.run(debug=True)
Wrapping up
This was definitely worth it because it allows me to quickly add new services and keep them organized. The fact that I used Blueprints makes it even more modular, keeping different services separated and easy to maintain.
If you’re interested, I created a starter kit to show how to implement multiple services using Blueprints. You can check it out on GitHub.
Any questions, hit me up on Twitter at @amit.
Happy coding!