Now, I know that using `app.run` is a legitimate way to run an app in a development environment. But here's the thing I've see again and again: People using `app.run` in production environments because they think they can run their Flask app like a node.js app while completely ignoring this message that pops up in red letters:
> WARNING: This is a development server. Do not use it in a production deployment.
Flask is not Express.js and Flask's internal dev server sucks for production. And it's a potential security risk if you leave debugging enabled. This is a statement you can find all over Flask's documentation.
> This launches a very simple builtin server, which is good enough for testing **but probably not what you want to use in production**.
- [Command Line Interface](https://flask.palletsprojects.com/en/1.1.x/cli/#run-the-development-server)
> [...] The development server is provided for convenience, **but is not designed to be particularly secure, stable, or efficient**.
- [Deploy to Production](https://flask.palletsprojects.com/en/1.1.x/tutorial/deploy/)
> When running publicly rather than in development, you should not use the built-in development server (`flask run`). **The development server is provided by Werkzeug for convenience, but is not designed to be particularly efficient, stable, or secure**.
So much for the development server. **But why not use `app.run` ever, not even while developing?** Not only is `flask run` the [recommended way](https://flask.palletsprojects.com/en/1.1.x/server/) to run an app while developing, I also think it creates a certain mindset. It eliminates the need for a dunder main construct which makes the Flask app practically not executable by passing it to `python`. That in turn makes it necessary to start a WSGI-compatible web server externally in any scenario. It want to believe that it makes people think about which environment they want to run the app in and whether to use `flask run` or `gunicorn`/`uwsgi`/`mod_wsgi`.
**tl;dr**: `app.run` makes it look like running an app node.js-style by running the script directly is ok in production while in truth you *always* need an external WSGI-compatible web server to run Flask apps.
Thanks for coming to my TED Talk.
8 thoughts on “PSA: Don’t use app.run ever”
Thanks for creating the awareness
How can I run my app with a different method? Or which one is the safest for production?
answering incomming questions right away:
you can use, for example, waitress as wrapper for flask.
get it: pip install waitress
import it: from waitress import serve
run it: serve(app, host=’0.0.0.0′, port=5000)
you don’t even have to change anything in your code.
I just deployed my website to heroku, I’d really appreciate how to fix it (a tutorial?) since I think I am using app.run.
This should be pinned on top of the sub. I didn’t learn proper deployment until moving on to ASGI framework where you have to had another web server to run your app.
So easy to install and launch. All of 5 mins. Thanks to the Russians. 🙂
IF I’m deploying to a hosted service, specifically using Amazon Web Services Beanstalk, then as per the official documentation provided, I SHOULD use application.run right? Because the host actually takes care of serving the app, load balancing etc? I’m a web dev noob, thank you for understanding.
I’ve been advocating to use gunicorn in development and production for a long time too. It’s been like that for 5+ years in my Build a SAAS App with Flask course.
If anyone is curious how to set that all up, it’s in the source code at: https://github.com/nickjj/build-a-saas-app-with-flask
It handles using gunicorn, dealing with code reloading in development and also still gives you access to the in browser debugger. Files of interest would be config/gunicorn.py, snakeeyes/app.py#create_app (DebuggedApplication class) and the bottom of the Dockerfile for running gunicorn (CMD).
It also uses env variables for certain gunicorn options so that you can use the exact same config and setup in dev and prod, but then tweak certain env variables depending on where you run it. Such as using 1 gunicorn worker in development but X number of workers in prod.
Then for production I’d throw nginx in front of that, but that’s a discussion for another time.