Most Flask apps store data in SQL, and Flask-SQLAlchemy wires sessions to the request lifecycle for you.
Flask has no database layer of its own. The most common choice is Flask-SQLAlchemy (pip install flask-sqlalchemy), which integrates SQLAlchemy 2.x:
db = SQLAlchemy(model_class=Base)whereBasesubclassesDeclarativeBase- configure
SQLALCHEMY_DATABASE_URI, such assqlite:///app.dborpostgresql+psycopg://... - models subclass
db.Modelwith typed columns:id: Mapped[int] = mapped_column(primary_key=True) - queries use SQLAlchemy 2.0 style:
db.session.execute(db.select(User).where(User.name == "ann")).scalars().all(), ordb.session.scalars(...) - shortcuts for views:
db.get_or_404(User, id),db.first_or_404(stmt),db.paginate(stmt, per_page=20)
db.session is scoped to the app context, so each request gets its own session, and Flask-SQLAlchemy removes it when the request ends. You still decide when to write: db.session.add(obj) then db.session.commit(). If something fails mid-way, db.session.rollback().
db.create_all() creates missing tables, which is fine for prototypes and tests but never alters existing ones. Real projects use Flask-Migrate (Alembic) to generate and apply schema migrations.
Avoid the legacy User.query.filter_by(...) API in new code; it still works, but SQLAlchemy 2.0 style db.select is the documented approach.
If you prefer no ORM, Flask's tutorial shows plain sqlite3 with a connection stored in g and closed in teardown_appcontext.
Example
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column
class Base(DeclarativeBase): pass
db = SQLAlchemy(model_class=Base)
class Note(db.Model):
id: Mapped[int] = mapped_column(primary_key=True)
text: Mapped[str]
app = Flask(__name__)
app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///:memory:"
db.init_app(app)
@app.post("/notes/<text>")
def add(text):
note = Note(text=text)
db.session.add(note); db.session.commit()
return {"id": note.id}, 201
@app.get("/notes/<int:nid>")
def show(nid):
return {"text": db.get_or_404(Note, nid).text}
with app.app_context(): db.create_all()
c = app.test_client()
print(c.post("/notes/hello").json, c.get("/notes/1").json, c.get("/notes/9").status_code)
# {'id': 1} {'text': 'hello'} 404Remember
- Flask-SQLAlchemy gives db.Model, db.session and Flask-aware helpers
- Query with db.select(...) and db.session.execute/scalars (SQLAlchemy 2.0 style)
- Commit explicitly; use Flask-Migrate for schema changes
Watch out for
- Relying on db.create_all() to apply schema changes to an existing database; it only creates missing tables.