Quart: the async Flask rewrite that depends on Flask
An async Python micro framework for building web applications.
At a glance
- What is it?
- Quart is a Python web framework with the same API as Flask, written for asyncio, and it is the easiest way into async web development for anyone who already knows Flask. Two details in its packaging are worth more attention than its feature list: Flask is a runtime dependency of the thing that reimplements Flask, and the release line moved three versions in one afternoon last September.
- Who is it for?
- Quart fits a team that already knows Flask and needs request handling that does not block a loop, since the API, the extension ecosystem and even the migration path are the ones you already use. Three things to check before you commit.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 63 days ago.
- What is it written in?
- Mainly Python, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on November 13, 2026, and from our analysis. They are not legal advice.
Star history
- pallets/quart3,682 ★ · +9
| Repository | 2026-09-24 | 2026-11-13 |
|---|---|---|
| pallets/quart | 3.7k | 3.7k |
9 Stars in the last 50 days, measured from the daily GitHub snapshot. Compare with other projects
Editorial analysis
Flask is a runtime dependency of the framework that reimplements Flask
The relationship with Flask is stated plainly: Quart is an asyncio reimplementation of that framework, and if you understand Flask you understand Quart.
What is less obvious is in the manifest. The runtime dependencies are a file-handling library for async work, a signalling library, the command line library, a minimum version of Flask, an ASGI server, a token-signing library, a template engine, its escaping helper, and a minimum version of the web toolkit. So the reimplementation depends on the thing it reimplements.
That is a deliberate architectural position rather than an oversight, and the dependency list is the proof of it. The libraries around Flask, the toolkit, the template engine, the command line parser, the token signer, the escaper and the signalling helper, are all consumed by Quart directly rather than forked, and the only genuinely new pieces in the list are the async file layer and the ASGI server.
The packaging reflects the same relationship in two other places. One of the project's classifiers names the Flask framework explicitly, so package indexes can filter by it, and the documentation says a number of Flask extensions work with Quart.
For an application, the practical consequence is that upgrading Quart and Flask is one dependency graph rather than two.
The migration path is a find and replace plus two keywords
Most framework migrations get a long document. This one gets three sentences.
It should be possible to migrate from Flask by replacing the module name throughout your project and then adding the async and await keywords, and the documentation has a longer guide for anyone who needs it.
Two things are worth noticing. The claim is hedged, in the way a maintainer hedges when the common case is easy and the edges are not, and the hedge covers exactly the edges: a Flask application that blocks on a synchronous library cannot be fixed by a search and replace, because the blocking call has to become an async one or move to a thread.
The extension claim in the previous section is the second half of the migration story. Because Quart shares Flask's libraries, extensions written against those libraries mostly work, and the ones that do not are the ones that reach into internals Quart does not copy.
So the realistic shape of a migration is: the routing, the templates and the request handling move over almost mechanically, and the database calls and anything else synchronous do the work.
Three releases in one afternoon, and a framework still classified as a beta
The release history is three entries and they were published within about three minutes of each other.
They cover a minor version, its patch, and the previous minor version, and all three went out on the same afternoon in September 2026, with the default branch pushed that same morning. So a major version boundary and two accompanying releases shipped as one coordinated event rather than as a sequence.
That is what a well-run release looks like from the outside, and the tree supports it: there is a changes file at the root, a pre-commit configuration for keeping the tree clean, and the documentation site has its own changes page linked from the project metadata.
The classification is the counterpoint. The project metadata lists the development status as a beta release, with the trove classifier for it, which is a framework that has existed for years and shipped a new minor version that afternoon and still calls itself a beta.
Read that as a statement about the compatibility promise rather than about the code. A beta classification in a project with a documented migration story and a stable extension ecosystem means the API may still move between minors, and it is the reason to read the changes file rather than assume a minor bump is routine.
Seven dependency groups, two type checkers and a property-testing library
The development dependencies are organised into groups rather than one list, and the groups tell you what the maintainers consider separable jobs.
There is a development group with the linter, the test matrix runner and its async-aware companion. A documentation group with a Markdown parser, a theme and the generator itself, plus a separate group containing only the live-rebuild tool for the documentation server. A pre-commit group with the hook runner and its environment-managed companion. A typing group with two independent type checkers, a test runner and type stubs.
And a tests group with the test runner, its async plugin, coverage, a progress reporter, the dotenv library, and a property-based testing library.
That last one is the interesting entry. Property-based testing in a web framework's own test dependencies means somebody is testing behaviour with generated inputs rather than hand-written cases, which is the right tool for a framework whose surface is large and whose inputs are arbitrary.
One more group is worth calling out: the group that updates the workflow files is gated on the Python version, so it only installs on newer interpreters. That kind of marker in a group entry is how a project keeps one tooling job from breaking the oldest runtime it supports.
The Python floor is 3.13, the project ships its own types, and it has one extra
Three packaging facts tell you what kind of library this is.
The interpreter floor is a specific recent release rather than a range, which means installing it on anything older fails immediately rather than at import time. That is a deliberate choice for a project whose dependency chain includes async-aware releases of its own libraries.
The project ships type information, and it says so in its classifiers with the marker for typed packages. Given that the typing development group runs two independent type checkers over the source, the claim is backed by tooling rather than aspiration.
And there is exactly one optional extra, for loading environment files from disk, which is the kind of dependency most frameworks make mandatory. Keeping it optional means the framework does not decide how you configure it.
The project also registers its own command, so installing it gives you a way to run a development server without writing a script. The quickstart's output line names the loopback address it binds and the port it chose, which is the default you will be overriding in production.
The quickstart covers templates, JSON and WebSockets in fifteen lines
The example in this README is short enough to read twice, and it is chosen to show three different kinds of handler.
A route returns a rendered template, and the handler is async and awaits the render. A second route returns a plain dictionary, which the framework serialises as JSON, and it is async without needing an await inside. A third is a WebSocket route that loops forever sending a string and then a JSON object:
@app.route("/api")
async def json():
return {"hello": "world"}
@app.websocket("/ws")
async def ws():
while True:
await websocket.send("hello")
await websocket.send_json({"hello": "world"})Three things fall out of those fifteen lines. The route decorator takes the WebSocket path the same way it takes an HTTP path. Handler functions are coroutines, and a handler with nothing to await still is one. And the WebSocket object is a parameter you call methods on, rather than something you receive.
The run command is one word after the install, and its output tells you the address and port it bound and how to stop it.
For deployment, the README does not guess. It links a separate tutorial, which is the right call for a framework where the answer depends on your server and your process manager.
Four example applications, and a cheatsheet before a forum
The examples directory has four applications in it, and the choice of four is informative.
One is an API, one is a blog, one is a chat application, and one serves video. Between them they cover the three things the README advertises plus the combination of them: a chat application is a WebSocket with state, and video is streaming with range requests.
So the example set answers the question the quickstart raises. The quickstart shows that the primitives exist; the examples show what they look like assembled.
The help section is short and ordered. It says the documentation and a cheatsheet are the best places to start, and only then mentions the discussions tab and the chat server. A cheatsheet as the recommended starting point is an unusual choice for a framework that has a full manual, and it suggests the audience is people who know the synchronous equivalent of this framework and want the mapping rather than the tutorial.
Contributing is the conventional shape: an issue for bugs and features, a contributing guide for fixes, and a chat server for everything else.
Editorial conclusion
Quart fits a team that already knows Flask and needs request handling that does not block a loop, since the API, the extension ecosystem and even the migration path are the ones you already use. Three things to check before you commit. Flask is a real dependency in the install tree, so an async Flask application and Quart share one set of libraries, which is convenient until you want them on different versions. The project is classified as a beta release, and its documented migration path is a find and replace plus two keywords, which is a claim about the common case rather than a promise. And the floor is a recent Python, so check your runtime before reading anything else.
Frequently asked questions
What is Quart?
An asyncio Python web application framework with the same API as Flask, which can render and serve templates, return JSON, serve WebSockets, and stream request and response data. Its manifest describes it as an ASGI web framework with the same API as Flask.
Does Quart depend on Flask?
Yes. Its runtime dependencies include Flask itself along with the command line, templating, token-signing, escaping, signalling and web toolkit libraries Flask uses, plus an async file library and an ASGI server.
How do I migrate a Flask application to Quart?
The README says it should be possible to replace the module name throughout the project and then add the async and await keywords, with a longer migration guide in the documentation. It also says a number of Flask extensions work with Quart.
Which Python versions does Quart support?
The manifest requires Python 3.13 or later. The project also ships its own type information, declares itself typed in its classifiers, and offers one optional extra for loading environment files.
What examples does the Quart repository contain?
Four example applications: an API, a blog, a chat application and one that serves video, alongside the quickstart that demonstrates a template route, a JSON route and a WebSocket route.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/pallets-quart)Star history chart for your README
[](https://hysenlabs.com/projects/pallets-quart)Was this useful?