Hey there! Over two years later, I’ve made a (hopefully improved) post about application factories and blueprints.
I’m hoping to share some tips from developing and deploying several large Flask applications, some which aren’t obvious from the documentation.
Tip 1: Always use an application factory
The documentation does go over application factories, but completely glosses over most benefits.
App factories have a pretentious name, but basically they wrap the initialisation of the application in a method. Sounds like the obvious way to do it, but many Flask examples put the init code inside the module so that when you import the module the application is initialised. This sounds easier, but actually makes it harder in the long run, when you want to control initialisation.
TL;DR: Application factories get you:
- Easier deployment
- Clearer dependencies
Example 1: Deployment
Your production application will have a different configuration than the debug one. One (terrible) solution is “intelligent” configuration files that use environmental variables or hostnames, and it usually goes wrong. With an app factory, you can easily tell it which config to use:
from example import app # app is already initialised # can't change the config or database connection from example import create_app # app isn't initialised, we just imported the factory app = create_app(DB_CONN="production") # now it's initialised
Remember that the factory can provide default configuration values. So the development server script looks roughly like this:
from example import create_app if __name__ == '__main__': app = create_app() app.run() # using the default, debug database connection
But the WSGI script looks like this:
from example import create_app application = create_app(DB_CONN="production")
Much less chance of nuking the production database.
Example 2: Dependencies
By not having an initialised application to import, you have to be much more clear about dependencies. This is a good thing, especially if you want your application to grow. Personally, I find it demystifies relationships and avoids circular import hell. People are put off by late initialisation, but it’s really easy. For example, when you use SQLAlchemy, you need a database object:
# __init__.py app = Flask(__name__) db = SQLAlchemy(app) # models.py from example import db class User(db.Model): pass
When you use an app factory, this won’t work any more. But it does give you the opportunity to express the relationships more clearly:
# __init__.py def create_app(): app = Flask(__name__) from example.models import db db.init_app(app) return app # models.py db = SQLAlchemy() class User(db.Model): pass
Now the database object lives with the other database functionality, and is only initialised later. It doesn’t seem like much, but suddenly writing blueprints is also easier: If you need anything database related, you only need to import from
Blueprints allow for modular applications, are a great idea, and pretty much the only way to keep the codebase of medium or large applications sane. Using an app factory forces you to use blueprints, this is a good thing (see Google for now, maybe I’ll write about this later).
Example 3: Testing
Really, this is just example 1 again.
Good luck with Flask!