Open-source project
pallets-eco/flask-sqlalchemy avatar
pallets-eco/flask-sqlalchemy

Flask-SQLAlchemy: SQLAlchemy Support for Flask, Without the Boilerplate

Adds SQLAlchemy support to Flask

4,307 stars907 forksPythonBSD-3-Clause

At a glance

What is it?
Flask-SQLAlchemy wires SQLAlchemy 2.0 into Flask's application and request lifecycle. It is a small integration layer, not an ORM of its own, and the version pairing is what decides whether it fits your stack.
Who is it for?
Adopt Flask-SQLAlchemy if you already run Flask with SQLAlchemy 2.0.16 or newer and want db.session, db.Model and db.create_all() managed for you; skip it if you want a single SQLAlchemy setup shared with non-Flask code. Before committing, run pip install Flask-SQLAlchemy in a throwaway virtualenv and confirm that the installed flask and sqlalchemy satisfy the flask>=2.2.5 and sqlalchemy>=2.0.16 floors, because those two lower bounds are the whole compatibility story.
Can I use it commercially?
Yes. BSD-3-Clause 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 134 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 27, 2026, and from our analysis. They are not legal advice.

Editorial analysis

What Flask-SQLAlchemy actually adds on top of SQLAlchemy

The README describes the project as an extension for Flask that adds support for SQLAlchemy, aiming to simplify using SQLAlchemy with Flask through defaults and helpers for common tasks. That sentence is the scope. The ORM, the engine, the dialect layer and the query language all remain SQLAlchemy's; Flask-SQLAlchemy supplies the glue between them and a Flask application object.

The audience is narrow and specific. If you are writing a Flask application that talks to a relational database and you have already decided on SQLAlchemy as the ORM, this is the layer that saves you from re-implementing the same wiring in every project: engine creation from configuration, a scoped session, a declarative base that is aware of the app, and teardown on request or app context exit. If you are not using Flask, the project has nothing to offer you. If you are using Flask but prefer a different ORM or raw SQL, it is also irrelevant.

The packaging metadata is explicit about the two lower bounds: flask>=2.2.5 and sqlalchemy>=2.0.16, with requires-python>=3.8. Those numbers matter more than they look. They mean the extension targets the 2.0 style of SQLAlchemy, where select() is constructed and executed through a session, rather than the older Query-object idiom that many tutorials still show.

How the app context, db object and session fit together

The mechanism is visible in the README's example. You create a Flask app, set SQLALCHEMY_DATABASE_URI in app.config, define a DeclarativeBase subclass, and pass both the app and that base to the SQLAlchemy constructor via model_class. From that point the db object owns three things the application touches constantly: db.Model, the declarative base your tables inherit from; db.session, the session used for adds, commits and queries; and db.create_all(), which issues the DDL for the tables it knows about.

The example also shows the context requirement. The database work sits inside a with app.app_context(): block, and the session calls happen there. That is the design: the session is bound to the application context and cleaned up when that context ends, so a request gets its own session and does not leak state into the next one. Queries in the example go through db.session.scalars(db.select(User)), which is the SQLAlchemy 2.0 execution style rather than User.query.

The part worth flagging is the model_class argument. The README passes a custom Base into the constructor, and that is the modern pattern; it keeps your models on a base you control. Older code that calls SQLAlchemy(app) without model_class is relying on a default base the extension creates for you. Both appear in the wild, and the difference shows up the moment you try to share a base with a second library or split models across modules.

Installing Flask-SQLAlchemy and running a first query

The distribution name on PyPI is Flask-SQLAlchemy and the import name is flask_sqlalchemy; the two differ only by case and underscore, which is a common source of copy-paste errors. Install it into a virtual environment with pip:

bash
python -m venv .venv
source .venv/bin/activate
pip install Flask-SQLAlchemy

pip resolves the two declared dependencies, flask>=2.2.5 and sqlalchemy>=2.0.16, on its own. After installation, a minimal application that creates a SQLite file and inserts one row looks like this, following the README's example:

python
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column

app = Flask(__name__)
app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///example.sqlite"

class Base(DeclarativeBase):
    pass

db = SQLAlchemy(app, model_class=Base)

class User(db.Model):
    id: Mapped[int] = mapped_column(primary_key=True)
    username: Mapped[str] = mapped_column(unique=True)

Running that file writes example.sqlite next to the application. To create the table and insert a row, add the context block from the README:

python
with app.app_context():
    db.create_all()
    db.session.add(User(username="example"))
    db.session.commit()
    users = db.session.scalars(db.select(User))

The reader should see no output and no traceback; the row is in the file. Note that create_all() creates tables that do not exist yet and does nothing for tables that do, so it is not a migration tool. The repository keeps larger worked examples under examples/flaskr/ and examples/todo/ for anyone who wants a full application rather than a snippet.

Where the extension stops helping: migrations, schema drift and multi-app setups

The README documents create_all() and nothing about altering an existing schema. There is no migration command in the example, and the documentation does not present the extension as managing schema versions. That work belongs to a separate tool, and teams that assume otherwise discover it when a column rename silently does nothing on an existing database.

The session model is the second boundary. Because db.session is tied to the application context, code that runs outside a Flask context (a cron job, a standalone script, a worker thread that never pushed a context) cannot simply import db and query. It has to push an application context first, or take a different path to the engine. The README's example demonstrates this by wrapping everything in with app.app_context(), which is easy to miss when skimming.

The third boundary is application factory patterns. The README's example constructs SQLAlchemy(app, ...) directly against a module-level app. Flask applications that build the app inside a factory need the deferred initialization form instead, where the extension is constructed without an app and bound later. The README does not show that pattern in the excerpt available here, and anyone following the simple example literally into a factory-based project will hit an import-time application object that does not exist yet.

Finally, version pairing is a real failure mode rather than a theoretical one. The declared floors are flask>=2.2.5 and sqlalchemy>=2.0.16. A project pinned to SQLAlchemy 1.4 will not satisfy the dependency, and code written against the old Query interface will not match the select-based examples the README now uses.

Flask-SQLAlchemy versus using SQLAlchemy directly

The honest comparison is against plain SQLAlchemy, because that is what the extension wraps. With SQLAlchemy alone you create the engine yourself, build a sessionmaker, decide where the session lives, and manage its lifecycle in Flask's teardown hooks by hand. You also choose your own declarative base and your own way of reading the database URI out of configuration. None of that is difficult, but it is repeated in every project, and the details (scoped sessions, teardown ordering, thread safety) are easy to get subtly wrong.

Flask-SQLAlchemy trades that repetition for a dependency and a set of conventions. You get db.session, db.Model and db.create_all() with the lifecycle already handled. The cost is that your database layer now assumes Flask is present, so a shared model package used by both a Flask service and a non-Flask script must either push an application context or duplicate its engine setup.

A second alternative is to keep the two layers separate on purpose: define models on a plain DeclarativeBase and use a plain sessionmaker, then write a thin Flask integration of your own. That is more code but it keeps the models framework-agnostic, which matters if the same models are consumed by a CLI, a batch job or a second web framework. The README's model_class parameter is the extension's acknowledgement of this concern: you can hand it a base you already own, so the models themselves are not forced into a Flask-specific class.

Maintenance, release cadence and the BSD-3-Clause licence

The project sits in the Pallets Community Ecosystem, which the README describes as community maintenance of Flask extensions under the Pallets organization. That framing is worth reading carefully: Pallets maintains Flask itself, and this extension is maintained by the community around it, with the README inviting people to help on the Pallets Discord server.

The release history is uneven. Versions 3.1.0 and 3.1.1 both landed on 2023-09-11, and 3.0.5 on 2023-06-21. The most recent push to the default branch was on 2026-05-18, so the repository has seen activity long after the last tagged release. That combination, recent commits but no release since 2023, means anyone depending on a specific fix should check whether it is in 3.1.1 or only on main. Upgrading from 3.0.x to 3.1.x is the transition that matters most, because it is the line where the SQLAlchemy 2.0 style becomes the documented default.

The licence is BSD-3-Clause, declared in pyproject.toml as a file reference to LICENSE.txt and confirmed by the classifier. It is a permissive licence, so redistribution and modification inside commercial products are normal, but the copyright notice and disclaimer have to travel with the source. That is a general property of the licence text, not legal advice; if the notice placement matters to your organisation, read LICENSE.txt rather than a summary.

Editorial conclusion

Adopt Flask-SQLAlchemy if you already run Flask with SQLAlchemy 2.0.16 or newer and want db.session, db.Model and db.create_all() managed for you; skip it if you want a single SQLAlchemy setup shared with non-Flask code. Before committing, run pip install Flask-SQLAlchemy in a throwaway virtualenv and confirm that the installed flask and sqlalchemy satisfy the flask>=2.2.5 and sqlalchemy>=2.0.16 floors, because those two lower bounds are the whole compatibility story.

Frequently asked questions

What are the differences between SQLAlchemy and Flask-SQLAlchemy?

SQLAlchemy is the ORM and database toolkit; Flask-SQLAlchemy is an extension that adds support for it to Flask by providing defaults and helpers for common tasks. The README describes it as simplifying SQLAlchemy usage with Flask rather than replacing it.

What is Flask-SQLAlchemy used for?

It wires SQLAlchemy into a Flask application: you set SQLALCHEMY_DATABASE_URI in app.config, declare models on a DeclarativeBase passed as model_class, and use db.session, db.Model and db.create_all() inside an application context.

How to install Flask-SQLAlchemy?

Install the Flask-SQLAlchemy distribution with pip; the import name is flask_sqlalchemy. pip pulls in the declared dependencies flask>=2.2.5 and sqlalchemy>=2.0.16, and the package requires Python 3.8 or newer.

What is Flask-SQLAlchemy in Python?

It is a Python package that adds SQLAlchemy support to Flask applications, declared in pyproject.toml as Flask-SQLAlchemy with the module name flask_sqlalchemy. It requires Python 3.8 or newer.

How to use Flask-SQLAlchemy?

Create a Flask app, set SQLALCHEMY_DATABASE_URI, define a DeclarativeBase, and pass the app and base to SQLAlchemy via model_class. Then, inside with app.app_context(), call db.create_all(), add objects to db.session, commit, and query with db.session.scalars(db.select(User)).

Official sources

  1. License: BSD-3-Clause
  2. pallets-eco/flask-sqlalchemy on GitHub
  3. Project website
  4. README
  5. Releases
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.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/pallets-eco-flask-sqlalchemy.svg)](https://hysenlabs.com/projects/pallets-eco-flask-sqlalchemy)