APIFlask: a Flask-based Python API framework with marshmallow and Pydantic schemas
A lightweight Python web API framework. APIFlask supports both marshmallow schemas and Pydantic models through a pluggable schema adapter system, giving you the flexibility to choose the validation approach that best fits your project.
At a glance
- What is it?
- APIFlask wraps Flask with request validation, response serialization and OpenAPI generation, and accepts either marshmallow schemas or Pydantic models. It is for teams that want FastAPI-style ergonomics without leaving the Flask ecosystem.
- Who is it for?
- Adopt APIFlask if you already run Flask in production and want validation, serialization and an OpenAPI document without rewriting your routing, blueprints or extensions. Do not adopt it if you need ASGI performance characteristics or an async-native stack from the start, because the async path depends on the optional asgiref extra and Flask's own async support.
- 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 18 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 September 25, 2026, and from our analysis. They are not legal advice.
Editorial analysis
The gap APIFlask fills between plain Flask and a typed API framework
Flask gives you routing, blueprints and a request object. It does not give you a request body validator, a response serializer, or an OpenAPI document. Teams building JSON APIs on Flask therefore assemble that layer themselves: webargs or marshmallow for parsing, a serializer for output, and apispec plus hand-written annotations for the spec. APIFlask is that assembly, shipped as one package.
The target user is a team that already has Flask code and Flask extensions it cannot drop. APIFlask is a thin wrapper on top of Flask, and the README frames the migration as three changes: use APIFlask instead of Flask when creating the application instance, APIBlueprint instead of Blueprint, and apiflask.abort for JSON error responses. Everything else, the README states, is still Flask. That is a narrower promise than a new framework, and it is the honest one: the value is in the decorators and the generated document, not in a new runtime.
How the schema adapter system works with marshmallow and Pydantic
The mechanism is a pluggable schema adapter. APIFlask does not hard-code one validation library; it dispatches on the schema object you pass to the decorators. Pass a marshmallow Schema subclass and it uses marshmallow. Pass a Pydantic BaseModel and it uses Pydantic. The same @app.input() and @app.output() decorators accept either.
The data flow is: the decorator declares the expected input schema and output schema, the adapter deserializes and validates the incoming request, your view function receives already-parsed data, and the return value is serialized through the output schema before it leaves. Failures become JSON error responses rather than HTML error pages. The same declared schemas feed the OpenAPI generator, which is why the spec stays in sync with the code instead of drifting.
That design has a cost worth naming. Because both libraries are dependencies, the installed footprint includes marshmallow, flask-marshmallow, webargs, apispec and pydantic[email], not just the one you use. The pyproject.toml lists all of them as required, so choosing Pydantic does not remove marshmallow from your environment. If dependency surface is something you audit, that matters more than the feature list.
Installing APIFlask and serving a first validated endpoint
Installation is a single pip command. On Linux and macOS the README gives pip3, on Windows pip. Python 3.9 or newer and Flask 2.1 or newer are required.
$ pip3 install apiflaskSave the following as app.py. It defines an input schema with a length validator and an allowed-value validator, an output schema, and a list of pets to validate against.
from apiflask import APIFlask, Schema, abort
from apiflask.fields import Integer, String
from apiflask.validators import Length, OneOf
app = APIFlask(__name__)
pets = [
{'id': 0, 'name': 'Kitty', 'category': 'cat'},
{'id': 1, 'name': 'Coco', 'category': 'dog'}
]
class PetIn(Schema):
name = String(required=True, validate=Length(0, 10))
category = String(required=True, validate=OneOf(['dog', 'cat']))
class PetOut(Schema):
id = Integer()
name = String()
category = String()Run it with the Flask CLI in debug mode. The README uses flask run --debug.
$ flask run --debugWith the server up, two URLs are immediately useful. http://localhost:5000/docs serves the interactive documentation, Swagger UI by default. http://localhost:5000/openapi.json serves the generated OpenAPI document. You can also emit the spec without a running server by using the flask spec command, which APIFlask registers as a Flask CLI entry point.
Swapping the documentation UI and emitting the OpenAPI spec in CI
The docs_ui parameter on the APIFlask constructor changes which front end renders /docs. The README lists five accepted values: swagger-ui (the default), redoc, elements, rapidoc and rapipdf.
app = APIFlask(__name__, docs_ui='redoc')For CI, the flask spec command is the more interesting piece. It writes the OpenAPI document without booting a server, which means you can diff the spec between branches and fail a build when a schema change alters the public contract. The README does not document options for that command beyond its existence; check the OpenAPI documentation page for flags before wiring it into a pipeline.
One caveat on the UI list: rapipdf renders a PDF export of the spec, not an interactive console. It is a different kind of tool wearing the same parameter name.
Where APIFlask is the wrong choice
Async is the clearest boundary. The repository ships an async extra, installed with pip install -U "apiflask[async]", which pulls in asgiref. The README's own example uses async def with await asyncio.sleep(1) and points readers to Flask's documentation on async and await. That is Flask's async support, layered on a WSGI framework, not an ASGI-native stack. If your workload is dominated by concurrent outbound I/O and you want the server and the framework designed around that from the start, APIFlask is the wrong tool and you will feel it.
The second boundary is schema complexity. The adapter system gives you a choice of validation library, but the examples here show flat schemas: a name, a category, an id. Nested relationships, discriminated unions and polymorphism are where marshmallow and Pydantic diverge most, and where the adapter's translation between a schema object and an OpenAPI fragment is most likely to need manual correction. If your API is a graph of nested resources, prototype the ugliest payload you have before deciding.
The third boundary is team familiarity. APIFlask assumes you know Flask. If nobody on the team has written a Flask blueprint or a Flask extension setup, the three-step migration described in the README is three steps you cannot take.
APIFlask compared with flask-smorest and FastAPI
The README credits APIFlask as a fork of APIFairy, inspired by flask-smorest and FastAPI, and links a comparison page. The differences are structural, not cosmetic.
flask-smorest is the closest relative: marshmallow-based, Flask-based, OpenAPI-generating. The distinguishing feature of APIFlask is the adapter layer, which lets a single project use Pydantic models where the type-hint style fits and marshmallow where it does not. flask-smorest commits to marshmallow. If your codebase is already marshmallow-only and you like it, that commitment is not a disadvantage.
FastAPI is the other direction entirely. It is ASGI-native, built on Starlette and Pydantic, and its dependency injection system is central to how applications are structured. APIFlask keeps Flask's request context, its extension ecosystem and its WSGI deployment story. The trade is real in both directions: FastAPI buys you async concurrency and a different programming model, APIFlask buys you the Flask extensions you already depend on. Neither is strictly better; the question is which set of existing code you want to keep.
Maintenance, upgrade cost and the MIT licence
The repository is not archived. The most recent push recorded for it is 2026-06-19, which is the same date as the 3.1.1 release. Releases are spaced: 3.0.2 in November 2025, 3.1.0 in March 2026, 3.1.1 in June 2026. The pyproject.toml in the repository declares version 3.1.2, ahead of the published 3.1.1, and classifies the project as Production/Stable.
Upgrade cost is dominated by two moving parts: the Flask version floor (2.1 or newer) and the schema libraries. Since marshmallow and Pydantic are both required dependencies, a major version bump in either can reach you even if you only use the other. The changelog is the place to check before upgrading, and the repository keeps a CHANGES.md alongside it.
APIFlask is MIT licensed, which permits commercial and closed-source use. The dependency chain is not uniformly MIT: Pydantic is also MIT, marshmallow is MIT, Flask is BSD-3-Clause, and webargs and apispec come from the marshmallow-code organisation. If your organisation runs licence scanning, the transitive set is what you will be asked about, not APIFlask itself. This is a description of the licences named in the repository, not legal advice.
Editorial conclusion
Adopt APIFlask if you already run Flask in production and want validation, serialization and an OpenAPI document without rewriting your routing, blueprints or extensions. Do not adopt it if you need ASGI performance characteristics or an async-native stack from the start, because the async path depends on the optional asgiref extra and Flask's own async support. Before committing, verify three things on your own application: that your existing Flask extensions still load under APIFlask, that your chosen schema layer (marshmallow or Pydantic) covers the nested and polymorphic payloads you actually send, and that the generated /openapi.json matches the contract your clients already consume. The MIT licence and the entry-point based flask spec command mean the exit cost is low: worst case, you revert the app factory to Flask and keep the schemas.
Frequently asked questions
What is APIFlask and how does it relate to Flask?
APIFlask is a lightweight Python web API framework based on Flask, and the README describes it as a thin wrapper on top of Flask. It extends Flask's Flask and Blueprint objects with APIFlask and APIBlueprint, and adds request validation, response serialization and OpenAPI generation. Other than those substitutions and apiflask.abort for JSON errors, the README states you are still using Flask.
How do I install APIFlask with pip?
Run pip3 install apiflask on Linux or macOS, or pip install apiflask on Windows. It requires Python 3.9 or newer and Flask 2.1 or newer. An async extra is available separately as pip install -U "apiflask[async]", which adds asgiref.
Can APIFlask use Pydantic models instead of marshmallow schemas?
Yes. The README states APIFlask supports both marshmallow schemas and Pydantic models through a pluggable schema adapter system, so you can choose the validation approach per project. Note that pydantic[email] and the marshmallow packages are both listed as required dependencies in pyproject.toml, so installing APIFlask installs both libraries.
How do I get the OpenAPI spec out of an APIFlask app?
The generated OpenAPI document is served at /openapi.json while the app is running. You can also produce it without a server with the flask spec command, which APIFlask registers as a Flask CLI entry point. The interactive documentation lives at /docs, rendered with Swagger UI by default.
What is the difference between a Flask API and FastAPI?
FastAPI is ASGI-native and built around Pydantic and dependency injection, while APIFlask stays on Flask's WSGI request context and extension ecosystem. APIFlask's async support comes from the optional asgiref extra and Flask's own async and await handling, which the README points to. The practical difference is which existing code you keep, not which one is faster in the abstract.
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/apiflask-apiflask)