FastAPI vs Flask: Choosing the Right Web Development Framework

Kostya Stepanov
CodeX
Published in
15 min readJul 9, 2024

Written by Mary Moore, copywriter at Shakuro, and Aleksey Gureiev

When you enter an address in your browser, a request is sent to the remote server. There are multiple requests in fact (for the page contents, graphics, styles, etc.) and all of them are directed to the specific software for handling. The web server usually takes the static files, while the web application handles the requests that return page contents or perform operations.

Understanding Web Development Frameworks

Web applications may be written in different general-purpose programming languages. Writing web applications using just the standard libraries coming with the language is hard and error-prone. Besides, all of the applications are performing mostly the same tasks. They accept requests, parse data, validate data, perform any required actions or run queries for data, and finally render responses.

All of these steps are common between all applications and differ only in specifics. That is why web application frameworks and libraries exist. They take the burden of routine tasks off the shoulders of programmers while letting them focus on the most important part — the purpose of the application. However, which one to choose?

In this article, we’ll compare two such frameworks — FastAPI vs Flask — written in one of the most popular languages — Python. We’ll look at what they share in common and how they are different, so the next time you need a framework for your killer app, you’ll know where to look.

There are many and many other Python web frameworks that may deserve attention, but you should be careful choosing one or another. It may be hard to find a team comfortable working with them and you may end up with a project that is hard to support in the long run.

Let’s start with the first question — what is FastAPI?

What is FastAPI?

FastAPI is a modern Python web framework designed to build APIs with high performance and simplicity. Released in 2018 by Sebastián Ramírez, FastAPI is built on top of standard Python-type hints and uses ASGI (Asynchronous Server-Gateway Interface) protocol, which allows it to handle asynchronous requests efficiently. This framework is known for its strong focus on speed, security, and ease of use, making it an attractive choice for building robust web applications.

Features of FastAPI

FastAPI’s key features include:

  • Async/await support: FastAPI seamlessly supports asynchronous programming with Python’s async/await syntax, enabling developers to write efficient and scalable code.
  • Type hints: By leveraging type hints, FastAPI provides strong typing and automatic API documentation, reducing errors and improving maintainability.
  • Pydantic: FastAPI uses Pydantic for data processing, validation, and (de)serialization. Pydantic itself is very performant and its core has recently been rewritten in Rust for extra speed.
  • ASGI compatibility: FastAPI is designed to work with ASGI-compliant servers, such as Uvicorn, allowing for seamless integration with other frameworks and libraries.
  • Support for OpenAPI: FastAPI generates automatic OpenAPI documentation for APIs, making it easier to integrate with third-party tools and services.

Thanks to the wide range of tools available and the simplicity of declaring endpoints, models, schemas, and how they are tied together, it’s very fast to put together APIs from these building blocks. All of these features provide an intuitive and enjoyable experience.

Now, what is Flask Python?

E-Commerce Admin Dashboard Design Concept by Shakuro

What is Flask?

Flask is a micro web framework for Python, first released in 2009 by Armin Ronacher. Known for its flexibility and simplicity, Flask is designed to be lightweight and easy to use, making it an excellent choice for building small to medium-sized web applications. This framework is based on the Werkzeug WSGI (Web Server Gateway Interface) server and Jinja2 templating engine.

Features of Flask

Flask’s key features include:

  • Microframework: Flask is designed as a microframework, which means it only includes what you need to build a web application. This approach leads to fewer dependencies and easier maintenance.
  • WSGI support: Flask uses the WSGI protocol to communicate with web servers, making it compatible with most WSGI-compliant servers.
  • Template engine: Flask comes bundled with the Jinja2 templating engine, which provides powerful features for rendering templates and handling user input.
  • Extensive extension library: The Flask community has developed a wide range of extensions that can enhance the framework’s capabilities, such as support for databases, caching, and authentication.

FastAPI vs Flask : A Detailed Comparison

In this part, we provide a side-to-side comparison of the frameworks organized in sections.

Framework Setup

Both frameworks are easy to start working with. Both allow you to evolve the app structure as you go and do not impose any strict directory structure on the project. This can both be a plus (if you know what you do) or a weak side of both (if you are just starting and need some hand-holding).

Sample FastAPI application looks like this:

  • Install the framework:
shell
$ pip install fastapi
  • Create the main.py with your application code:
python
from fastapi import FastAPI

app = FastAPI()

@app.get("/")
def read_root():
return {"Hello": "World"}
  • Run the application in development mode (automatically reloads the server on code changes):
shell
$ fastapi dev main.py

Sample Flask application looks like this:

  • Install the framework:
shell
$ pip install flask
  • Create the main.py with your application code:
python
from flask import Flask

app = Flask(__name__)

@app.route("/")
def hello_world():
return "<p>Hello, World!</p>"
  • Run the application:
shell
$ flask -app main run

From the examples above comparing Flask vs FastAPI, you can see that both frameworks are configured similarly. Both require you to install them and create the main application file that exports the app variable with your application. After that, you just run the application.

One difference that should be obvious from above is the markup of the request handlers. We’ll be covering this next.

URL Handling

When a request comes in, the application needs to handle it somehow. Frameworks let us define functions that handle requests and use decorators to define requests to which routes (and which HTTP request methods) each such function handles.

Here’s how FastAPI does that:

python
from fastapi import FastAPI

app = FastAPI()


@app.get("/say/{message}")
async def say(message: str):
return {"message": message}

Here we take the app instance and use its get(“/say/{message}”) to decorate our handler function. This effectively adds the handler for the “GET /say/…” request that takes the message from the URL path parameter, puts it into the function argument with the same name, and then uses it in the return value. When you need a method different from “get”, you use its name (“post”, “put”, “delete” etc) in the decorator.

Flask is slightly different, but not by a large margin. Here’s an example:

python
from flask import request

@app.route('/say/<message>')
def say(message):
return {"message": message}

When we compare URL handling for Python FastAPI vs Flask, the handler in the latter is not a coroutine (no async prefix) and the decorator name does not reflect the HTTP method. Flask chose that pattern to let you specify multiple methods for the same handler. By default, it’s GET.

Both frameworks let you have middleware to add crosscutting concerns to your code and the request instance to reach for headers, cookies, and other low-level request details. But here they start to diverge.

FastAPI relies heavily on Python’s type hints for data coercion and endpoint documentation. Flask lets you do your own data transformations and gives you access to any aspect of the request via the request attribute.

Validating User Input

Usually, when a request comes in, be it from data or some JSON, you want to pass it through the validation of some sort to be sure it complies with the structure you expect. Of course, you can do that manually field by field, but it is not very productive and brings a ton of boilerplate code.

A widely accepted approach is to define the model, including types of fields, conditions, ranges, and even nested models as best as you can declaratively and then add a fair bit of code for the specific cases.

In terms of the Flask vs FastAPI comparison, FastAPI on the other hand has built-in support for data validation via Pydantic. Pydantic, while not the slowest piece of the app, has recently been rewritten in Rust to gain even more performance. Deep integration of Pydantic with FastAPI gives the transparency of converting incoming data (query parameters, JSON bodies, etc.) into Python classes and back. All with validation and data types coercion.

Here’s a simple example of the model used to represent the contents of the POST /posts request JSON body.

python
from fastapi import FastAPI
from pydantic import BaseModel, Field

class Post(BaseModel):
title: str = Field(
title=”Title of the post”,
max_length=300
)

body: str | None = None


app = FastAPI()

@app.post("/posts/")
async def create_post(post: Post):
# post.title
# post.body
return post

As you can see, it defines two fields of a string type. The body is optional with a default set to None. The title field has an extra validation on the maximum string length and the title of the field for the documentation.

When the request comes, FastAPI performs all data coercions and validations and calls your handler function after all is verified to be correct. If anything looks wrong, the HTTP error is raised.

What is Flask Python option here? Flask doesn’t have anything built-in for that. It provides various functions for accessing request parameters, headers, and body, but that’s about all it does. If you need more elaborate means of accessing, deserializing, and validating data, you should look for an external library. One of such libraries that we love and can recommend is Marshmallow. It lets you do all that and more.

Generating API Documentation

Every API (internal or external) needs documentation. The de-facto standard for documenting APIs is becoming OpenAPI specification. Documentation in this format is machine readable as it’s either in JSON or YAML and can be used to generate code (for clients and servers, depending on where the documentation originates). Besides, thanks to Swagger and Redoc, it can be rendered in human-readable form as a documentation website.

FastAPI supports the automatic generation of the documentation based on the data models that you define for requests and responses, your endpoint metadata, and some additional markup that you can add incrementally as necessary for more descriptions, examples, etc. The bare minimum you get is automatic. In addition to the standard endpoint documentation, FastAPI provides a means of documenting callbacks and webhooks that your API may provide. It’s something yet to be found in other frameworks.

If we compare FastAPI vs Flask, the second one is less prepared here. Although some libraries attempt to fill this gap, Flask itself does nothing to help you with API documentation out of the box. You are on your own here. Most likely, you will be writing documentation by hand.

Terraview Dashboard Design Concept by Shakuro

Database Integration

Chances are you will need the database to store data of your application. Generally, working with your database isn’t specific to the framework as it is in the details of your application implementation. Each of the reviewed frameworks just attempts to make your life easier in one way or another.

FastAPI suggests using its dependency injection mechanism to pass on the instance of the database session into the request handler function. Then pass this database session instance into your DAO code to query data or make changes. Here’s an example:

python
from fastapi import Depends, FastAPI, HTTPException
from sqlalchemy.orm import Session

from . import crud, models, schemas
from .database import SessionLocal, engine

models.Base.metadata.create_all(bind=engine)

app = FastAPI()


# Dependency
def get_db():
db = SessionLocal()
try:
yield db
finally:
db.close()


@app.post("/users/", response_model=schemas.User)
def create_user(user: schemas.UserCreate, db: Session = Depends(get_db)):
db_user = crud.get_user_by_email(db, email=user.email)
if db_user:
raise HTTPException(status_code=400, detail="Email already registered")
return crud.create_user(db=db, user=user)


@app.get("/users/", response_model=list[schemas.User])
def read_users(skip: int = 0, limit: int = 100, db: Session = Depends(get_db)):
users = crud.get_users(db, skip=skip, limit=limit)
return users

Flask, on the other hand, provides no such dependency injection mechanism. There’s an extension named Flask-SQLAlchemy for those using SQLAlchemy for data access that helps you deal with it similarly.

Asynchronous Programming

This one is interesting, so read it carefully. Since version 3.4 Python acquired an additional concurrency paradigm — async coroutines. Previously there were just processes and threads. Simply put, processes are used to run code on available CPU cores while threads let us run code within the same process in a multiplexed way. The underlying OS is deciding which process to execute on a CPU core itself and switching context between threads at roughly the same intervals (for the threads and processes with the same priority).

With the coroutine introduction to Python, a new pattern emerged. Now the code can give up control to other coroutines voluntarily while it’s waiting for something to happen. Usually, it’s I/O or sleep cycles that require no active “doing”. For example, when your app talks to a database, it sends the request and waits for the response while the database looks for data and sends it back. This valuable CPU time was previously wasted. Now the code waiting for the database response has an option to give a chance to another piece to work and do something useful.

When we talk about web frameworks there are two specifications:

  • WSGI (Web Server Gateway Interface) — synchronous handling of requests from the web server. This is the initial model that will be familiar to PHP and Ruby programmers as well. It’s based on synchronous handling of requests by the dedicated pool of workers (processes and threads).
    Flask natively supports this specification. There’s no sense in running FastAPI under the WSGI server. However, FastAPI allows you to mount other WSGI apps inside it.
  • ASGI (Asynchronous Server Gateway Interface) — newer asynchronous handling of requests employing the async coroutines. This specification allows you to use all the benefits of the requests handling based on coroutines. FastAPI supports this specification natively. Flask can support it via the middleware adapter.

Generally, you should be looking for ASGI support as it gives the best bang for the buck.

Extensibility

In Python FastAPI vs Flask showdown, both of them are pretty extendable. Many external libraries provide functionality for just about anything you need to build web applications.

Both let you write middleware that wraps the request and lets you hook specific code before, after, and around the request handler.

Both provide lifecycle events that let you hook into the framework lifecycle to initialize your own modules and processing threads in a pretty flexible way.

Templating and rendering

If all you need is rendering JSON in your API application, that (in its simple form) is achieved by returning Dicts from your handlers.

FastAPI has more options by the ability to use Pydantic data models as serializers. When you dump your data you can customize the names of fields using aliases, skip unset fields, and do many other things.

Flask has no such instruments for customizing the output. One option is to use the Marshmallow library to serialize your data.

When it comes to Flask vs FastAPI comparison in rendering HTML, both rely on the Jinja2 templating library. Jinja2 is simple and flexible. It has a tiny templating language with loops, conditions, filters, and inclusions. You pass your variables from the Python code and can use them in templates. There are numerous articles and code samples for just about any aspect of this.

Mining Dashboard Design Concept by Shakuro

Running background tasks

There are certain things you either need to run on schedule or as the result of the request that you don’t want to block. Generating reports, sending emails, importing / exporting data — all are things that shouldn’t be run in the request handler. All of these tasks should be handled separately by a background task processor.

Although FastAPI provides an easy mechanism to run tasks after returning the response, we strongly recommend considering a dedicated tool for that. Look at Celery, for a good example.

Flask doesn’t even attempt to handle that as part of the framework. However, they provide an example of doing that with Celery as well.

WebSockets and SSE

Almost any application these days has in-app notifications, chats, or other real-time features. These are implemented either with WebSockets or Server-Sent Events depending on whether half-duplex or duplex communication is required.

FastAPI supports both out of the box. It’s no harder to set up a WebSocket or SSE endpoint than it is for any other. Thanks to asynchronous processing mode, these endpoints aren’t likely to take all your workers and block the traffic.

Flask doesn’t provide WebSockets or SSE out of the box. However, you can add support for them with the third-party libraries at your own risk.

This is the point you should pay close attention to. If anything above could be taken lightly, the decision to support WebSockets may seriously push you towards the web framework and server that support ASGI specification. Otherwise, you risk building something that will be hard to make fly. FastAPI may be a clear winner here of these two.

Development

When you are developing the application certain pleasantries make your life a bit easier. During FastAPI vs Flask showdown, there are some benefits we can pinpoint:

FastAPI provides the rendering of OpenAPI documentation at “/docs” and “/redoc” URLs out of the box so you don’t need to worry about rendering it yourself. Also, it provides hot reloading of the changed code when the application is started with “fastapi dev”. It has nice error reports with a ton of useful information nicely arranged on the screen, so it’s easy to make sense of it.

Flask isn’t that friendly with documentation and error reporting, but it also provides hot code reload. For generating documentation you should use an extension.

Testing

No one likes writing tests, right? Wrong. We do. The secret is in using the right tools for the job. It should be pleasant to work with, inspire confidence, and don’t stand in the way.

FastAPI provides an extensive toolkit for integration testing. You don’t need to launch the web app to make a query. All is hidden behind a tiny test client interface you call with request data and receive the responses just like a method on any other Python class.

Flask is on par with FastAPI here. They provide a similar approach to the test client. It’s as easy to make calls and analyze responses.

Administration UI

When building web applications, you have to provide back-office functionality in the form of an admin UI. Probably the most prominent example in the Python world is the Django Admin interface that comes with the framework and is there for you to use right away. But since we are comparing Python FastAPI vs Flask, we’ll focus on the options for them.

Flask has Flask Admin, which is a well-known library in the space. It’s battle-tested and has lots of nice features, including integration with the famous SQLAlchemy and mongoengine database engines.

FastAPI has a couple that are somewhat similar.

  • FastAPI Admin is opinionated and said to be inspired by the Django Admin. It uses TortoiseORM for database connectivity, tabler for lists rendering, and requires Redis to run. Depending on your choice of tools, this may not be exactly what you would like to run.
  • Starlette Admin is slightly more tolerant. It looks mostly the same due to the reliance on the same toolkit — tabler, but has a wider range of database adapters and no dependency on Redis.
Team Management Calendar UI Dashboard by Shakuro

Community & Support

You will find support with both of these frameworks. The Python community is vast. Flask has been on the scene for a very long time. Many developers love and use it in a ton of commercial applications.

FastAPI is newer, but it has much attention due to its modern features and excellent productivity. The community may be less, but you won’t need as much support as well.

We’d say, you won’t experience any difficulties finding a helping hand with either of them.

Usage Differences

Both frameworks are great. Flask is great for small to medium web apps. Either API-only or full-on web applications, it covers them all.

FastAPI, while focused primarily on API applications, can also be used for HTML-rendering applications due to its templating and statics support.

Technically, there’s not much of a niche you should be favoring one framework over another in. Take one whichever you prefer.

Final Verdict: Which Framework Should You Use & When?

We hope that now you’ve got a better understanding of which of these two beautiful frameworks better fits your needs. If not, here are our guidelines based on the Flask vs FastAPI comparison we made above:

  • If you are building an application and want to be all modern FastAPI is probably your best bet. It provides all imaginable features of the modern API application (and not only API) with style and convenience. Its popularity is high and still on the rise, so you won’t have a hard time building the team around it. Learning it will also be a breeze.
  • If the footprint of the app is important to you or maybe you have a team who is more proficient with Flask, Flask is a great framework too. You won’t get as many bells and whistles as you’d get with FastAPI, but you get a huge community and market, so it’s hardly an outlier.

As you might have guessed already, our recommendation is — FastAPI. There’s no compromise in doing that. It’s great however you look at it.

Originally published at https://shakuro.com

--

--

Kostya Stepanov
CodeX
Writer for

I'm Kostya, the founder of Shakuro. For 16 years, I've been helping companies and individuals worldwide create and enhance digital products.