Definition
A Python program runs on your machine, prints its result and ends. No visitor can trigger it from a browser: between the address they type and the function you wrote, a whole protocol is missing, the one the web runs on. Flask is that missing link.
This minimal web framework maps an address to a Python function and takes care of everything standing between the two: reading the request, pulling out what the visitor asked for, picking the status code, sending the answer back.
Beyond that, it decides nothing on your behalf: no database imposed, no admin interface, no account system. You only learn what you actually need, but you will wire up yourself what other frameworks hand over already in place.
Here is a complete application. Not an excerpt: the whole file.
from flask import Flask
app = Flask(__name__)
@app.route("/hello/<name>")
def hello(name):
return f"Hello {name}"The @app.route is a decorator: it runs nothing, it registers the function in the address table so Flask knows who to call when the request comes in. <name> becomes the argument of the same name: /hello/Marie answers Hello Marie. The rest is plain Python, with the same def and the same dictionaries as anywhere else.
The problem it solves
To measure what it brings, picture doing without it: opening a port, interpreting the first line of an HTTP request, splitting the headers, guessing the body encoding, building a valid response. None of that is what your application is about, and none of it changes from one project to the next.
So it replaces two things: the http.server module, barely able to serve the files of a folder, and the few hundred lines every project used to rewrite in order to turn an address into a function call.
One confusion comes up here, so let us clear it: Flask is not a competitor to requests. Both speak HTTP, in opposite directions. requests goes out to question an external service, Flask waits to be questioned. A single project often uses both together.
Flask, Django or FastAPI
The honest comparison is not about the number of features, it is about the number of decisions. Flask lets you choose, Django has already chosen for you. What settles it is how much time you accept spending on decisions.
The table reads in that direction: on the left what Flask leaves open, on the right what Django has closed.
| Topic | Flask | Django |
|---|---|---|
| Database | Plugged in by hand | Provided, with migrations |
| Admin interface | Nothing, or an extension | Generated automatically |
| File layout | Free, so up to you | Imposed, so identical everywhere |
| First screen shown | Six lines | One command and several files |
| Fifty-page application | You rewrite what Django offers | Already there |
Flask wins at the start, Django wins over time: a growing project ends up asking for accounts, migrations and an admin screen, and you will rebuild them piece by piece.
FastAPI holds a third and more recent place: the same lightness as Flask, but incoming data validation and interface documentation are both derived from type hint declarations. For a service returning nothing but json, it has become the default pick. Flask keeps the edge on projects serving real HTML pages, or when the extension you need already exists.
Databases, user login and migrations do exist on the Flask side, but as separate extensions: Flask-SQLAlchemy, Flask-Login, Flask-Migrate. They are chosen one by one, and the Flask team does not maintain them.
When it is of no use
A script launched by a scheduled job, a file-processing routine, a computation inside a notebook: none of that needs Flask. Those programs already have someone to trigger them, and that someone is not a browser.
Installing it just in case costs more than it looks: one more dependency, a process that has to stay up, an exposed surface to watch over, all for a feature nobody uses. A brochure page is the same calculation: a static HTML file loads faster and breaks less often.
The three traps when discovering it
The first one is the development server. The launch command starts a server meant for a single person, the one writing the code, and it says so itself in the console. Going live means an application server such as Gunicorn, which runs several processes.
The second one is state kept in a global variable. A counter filled request after request works perfectly on your machine, where a single process runs. In production several processes run side by side and each keeps its own copy: the value changes on every reload, with no error raised to warn you. So whatever must outlive a request belongs in a database or a cache.
The third one is not paid in lost time but in security, and it concerns debug mode.
That mode opens a console in the browser on the slightest exception, one able to run Python on the server. While writing code, it is the best diagnosis tool there is. Live, it is access to your machine handed to the first visitor who triggers an error.
Frequently asked questions
Is a virtual environment really needed to install Flask?
Yes, for the same reason as any library. Installing with pip into the system Python mixes the versions of all your projects: upgrading Flask for one changes the version another one sees, without warning, and the breakage surfaces weeks later. One virtual environment per application keeps those dependencies apart.
Why can my file no longer find Flask after I named it flask.py?
Because Python looks in the current folder first. Your file takes the library's place, and import brings back your own code, which holds none of what Flask exposes. The symptom is a ModuleNotFoundError or a puzzling attribute error. Rename the file, then delete the __pycache__ folder, which keeps a compiled version of the old name.
Can Flask handle a heavily visited website?
Flask is not what absorbs the load, the application server in front of it does, along with the number of processes granted to it. The real limit lies elsewhere: each request holds a process from start to finish, so one slow call to an external service ties that slot up. On that profile, a framework built on asyncio hands control back during the wait.