# Flask: the WSGI framework that suggests a layout instead of enforcing one

> Flask is a small Python web framework built on Werkzeug and Jinja. It is a good fit when you want to choose your own database, template and project structure, and the wrong fit when you want those decisions made for you.

**pallets/flask** — Flask is a small Python web framework built around Werkzeug and Jinja, with extensions available for larger applications.

- Repository: https://github.com/pallets/flask
- Website: https://flask.palletsprojects.com
- Stars: 74,779 · Forks: 17,006
- Language: Python
- License: BSD-3-Clause
- Published: 2026-08-08 · Updated: 2026-08-18 · Language: en
- Canonical page: https://hysenlabs.com/projects/pallets-flask

## What Flask is for, and who it is not for

Flask is a WSGI web application framework. The README describes it as lightweight and says it is "designed to make getting started quick and easy, with the ability to scale up to complex applications." That sentence contains the whole pitch and the whole trade-off. Getting started is short: one file, one import, one route decorator, one command to run it. Scaling up is left to you.

The README is explicit that Flask "offers suggestions, but doesn't enforce any dependencies or project layout," and that "it is up to the developer to choose the tools and libraries they want to use." There is no bundled ORM, no migration tool, no form library, no admin panel. If you have opinions about your stack, that is freedom. If you do not, it is work you have to do before your application does anything useful.

The intended audience is a developer who already knows Python and is willing to assemble the rest. The pyproject.toml lists the runtime dependencies as blinker, click, itsdangerous, jinja2, markupsafe and werkzeug, which is a deliberately short list. Nothing in it decides how you store data.

## How Flask sits on Werkzeug and Jinja

Flask began as a wrapper around Werkzeug and Jinja, and that is still the shape of it. Werkzeug handles the WSGI layer: the request and response objects, routing, and the development server that backs the flask run command. Jinja handles templating. Flask itself is the glue that ties an application object to routes, configuration, sessions and extensions.

The application object is created with app = Flask(__name__). Routes are registered by decorating a function with @app.route("/"). When a request arrives, Werkzeug matches the URL, Flask calls the matching view function, and whatever the function returns becomes the response body or is converted into one. If you return a string, Flask builds the response for you.

Because the interface is WSGI, the development server is not the deployment story. In production a WSGI server such as Gunicorn or uWSGI imports the application object and calls it. The repository also exposes an async optional dependency group containing asgiref, which the pyproject.toml lists as async = ["asgiref>=3.2"]. That extra is opt-in; the README does not present Flask as an async framework, and the default request path is synchronous WSGI.

## Installing Flask and running the README example

Flask is published on PyPI under the package name Flask, so it installs with pip or with uv. The pyproject.toml sets requires-python = ">=3.10", which means an older interpreter will refuse the install rather than fail at runtime. The README does not spell out an install command, so the package name is the part to copy exactly.

```bash
python -m pip install Flask
```

After that, the README gives a complete application. It says to save this as app.py. The file imports Flask, creates the application object, and registers a single route that returns a plain string.

```python
# save this as app.py
from flask import Flask

app = Flask(__name__)

@app.route("/")
def hello():
    return "Hello, World!"
```

The README then shows the command that starts the development server, and the output it prints. The command is flask run, and the expected line is a URL on 127.0.0.1 at port 5000 with a note to press CTRL+C to quit.

```bash
$ flask run
  * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
```

If flask run cannot find the application, the usual cause is that app.py is not in the working directory or the FLASK_APP environment variable is unset. The README does not document that failure mode; it comes from the command's own conventions. Visiting http://127.0.0.1:5000/ should render the string from the view function.

## The optional extras and what they actually pull in

Two optional dependency groups appear in pyproject.toml, and they are narrow. The async group contains asgiref>=3.2. The dotenv group contains python-dotenv. Installing Flask without them is the default, and the README does not mention either one, so a reader who only reads the README will not know they exist.

That matters for two common expectations. First, environment variable loading from a .env file is not part of a bare install; it requires the dotenv extra. Second, async support is not part of a bare install either, and adding asgiref does not turn the framework into an async framework. The development groups in the same file (dev, docs, tests, typing, pre-commit) are for working on Flask itself, not for using it, and the typing group includes mypy, pyright and cryptography among others. Do not copy those into an application dependency list.

The project is typed: the classifiers include "Typing :: Typed", and the typing group exists to check that. That is a real benefit if you run a type checker over your own application, and it is one of the concrete differences between Flask and frameworks that ship annotations later or not at all.

## Where Flask is the wrong choice

The README's own framing is the limitation. Because Flask does not enforce a project layout, two Flask codebases can share almost nothing structurally. There is no canonical place for models, no built-in migration path, and no framework-level convention that tells a new contributor where anything lives. On a team that grows, that cost lands on whoever has to read the code.

The second limitation is the WSGI request model. Flask's default path is synchronous. The async extra exists, but the README does not describe Flask as an async framework, and the pyproject.toml async group is a single package. If your workload is dominated by concurrent outbound I/O and you want the framework to be built around that model, Flask is not the tool the documentation describes.

The third is the development server. flask run is what the README demonstrates, and it prints a local URL on port 5000. That is a development convenience, not a production server. Nothing in the README describes running flask run behind a public address, and the WSGI design assumes a separate server process in front of it.

Finally, if you want batteries included, Flask is the wrong shape by design. The README points at community extensions rather than a first-party stack, which means the quality, release cadence and maintenance of your data layer, forms and auth are decisions you make per package.

## Flask compared with FastAPI

The comparison that comes up most often is Flask against FastAPI. The difference is architectural rather than cosmetic. Flask is a WSGI framework: synchronous by default, with an optional async extra that lists asgiref. FastAPI is built on ASGI and async from the start, and its documentation centres on request and response models declared with type hints.

In Flask you write a view function and return a value; the framework does not derive a schema from your annotations. In FastAPI the annotations are the schema, and validation and documentation are generated from them. That is a genuine trade: less code for the common API case, more framework opinion about how your handlers are written.

Flask's counter-argument is the one in its README. It does not enforce dependencies or layout, so it fits an application that is not primarily a JSON API, or one where the team has already chosen its own validation and serialisation libraries. If your application is mostly HTML rendered through Jinja, the FastAPI model buys you less. If it is mostly a typed JSON API, the FastAPI model does work you would otherwise write yourself. Neither is a strict upgrade; they optimise for different starting points.

## Maintenance, releases and the BSD-3-Clause licence

The repository is not archived, and the last push was on 2026-02-19, which is the same date as the 3.1.3 release. The two releases before that were 3.1.2 on 2025-08-19 and 3.1.1 on 2025-05-13. The pattern is occasional point releases rather than a constant stream of commits, which is what you would expect from a framework whose surface area is deliberately small.

The version in pyproject.toml on the default branch is 3.2.0.dev, so the branch carries unreleased work. If you install from PyPI you get a released version; if you install from the repository you get whatever the development branch currently is. The project publishes a Changes page at https://flask.palletsprojects.com/page/changes/, which is the place to check before upgrading rather than assuming a point release is behaviour-neutral.

Flask is licensed BSD-3-Clause, and the pyproject.toml declares license = "BSD-3-Clause" with license-files = ["LICENSE.txt"]. A permissive licence of that kind generally allows commercial and closed-source use, but the terms are in LICENSE.txt and nothing here is legal advice. The upgrade cost is mostly the cost of your extensions: Flask's own dependency floor is Werkzeug>=3.1.0 and Jinja2>=3.1.2, so a major Werkzeug change is the event that tends to ripple through an application. The README does not document a rollback procedure.

## Conclusion

Adopt Flask if you are comfortable choosing your own database, ORM, validation and project layout, and if a WSGI application that runs behind a separate server process matches your deployment. Do not adopt it if you want the framework to make those choices, or if your application is mostly async I/O, where the pyproject.toml async extra only lists asgiref and the documentation does not present Flask as an async-first framework. Before committing, verify your Python version against requires-python = ">=3.10" in pyproject.toml, and check the current release on the Changes page rather than assuming the version you read about is the one you will get.

## FAQ

### What is Flask used for?

It is a WSGI web application framework for building Python web applications, from a single-file example up to larger applications. The README says it is designed to make getting started quick and easy while scaling up to complex applications, and that it began as a wrapper around Werkzeug and Jinja.

### Is Flask or FastAPI better?

Flask is a WSGI framework whose README states it does not enforce dependencies or project layout, so you choose your own libraries. FastAPI is not described anywhere in this repository's material, so the comparison cannot be settled from these files; the honest difference is that Flask leaves validation and serialisation to your choices.

### What is Flask simple definition?

The README calls it a lightweight WSGI web application framework built around Werkzeug and Jinja, with community extensions for adding functionality. Its pyproject.toml describes it as "a simple framework for building complex web applications."

### How to use Flask?

Create an app.py containing from flask import Flask, app = Flask(__name__) and a function decorated with @app.route("/"), then start it with flask run. The README shows the server reporting a URL on http://127.0.0.1:5000/ and a note to press CTRL+C to quit.

### How to install Flask?

Install the PyPI package named Flask, for example with python -m pip install Flask. The pyproject.toml sets requires-python = ">=3.10", so the interpreter must be at least Python 3.10. Optional behaviour such as .env loading needs the separate dotenv extra.

### How to install Flask in VS Code?

The repository material does not describe a VS Code integration or extension; installation is the same PyPI package regardless of editor. Create a virtual environment for the interpreter you have selected, then install Flask into it.

## Sources

- [Official documentation](https://flask.palletsprojects.com)
- [Official README](https://github.com/pallets/flask#readme)
- [Project repository](https://github.com/pallets/flask)
- [Release notes](https://github.com/pallets/flask/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/pallets-flask
