100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace
Python

Flask-SQLAlchemy Basics

Learn how Flask-SQLAlchemy wires the SQLAlchemy ORM into a Flask app, from configuration to sessions.

Data & PersistenceBeginner8 min readJul 10, 2026
Analogies

What Is Flask-SQLAlchemy?

Flask-SQLAlchemy is an official Flask extension that wraps the SQLAlchemy ORM and adds Flask-specific conveniences: it manages engine creation from your app config, binds a scoped session to each request, and gives you a single db object that exposes both the ORM layer (db.Model, db.relationship) and the lower-level SQLAlchemy Core constructs (db.Table, db.session). Instead of hand-wiring a SQLAlchemy engine and sessionmaker yourself, you instantiate SQLAlchemy(app) once and Flask-SQLAlchemy handles connection pooling, teardown after each request, and multi-app testing patterns.

🏏

Cricket analogy: Flask-SQLAlchemy is like the BCCI providing a standard match-day protocol so every franchise in the IPL doesn't reinvent umpiring, DRS, and pitch reports from scratch each season.

Installing and Configuring the Extension

Configuration happens through Flask's app.config, most importantly SQLALCHEMY_DATABASE_URI, which follows the standard SQLAlchemy URL format such as postgresql://user:pass@localhost/dbname or sqlite:///app.db. In an application-factory setup, you create the SQLAlchemy() object at module level without an app, then call db.init_app(app) inside create_app() — this decouples the extension instance from any single app instance, which matters for testing multiple app configurations and avoiding circular imports between your models module and your app factory.

🏏

Cricket analogy: It is like a stadium's pitch curator setting soil composition and grass length weeks before a Test match — the configuration is prepared independently of which two teams (app instances) eventually play on it.

python
# extensions.py
from flask_sqlalchemy import SQLAlchemy

db = SQLAlchemy()

# app.py
from flask import Flask
from extensions import db

def create_app():
    app = Flask(__name__)
    app.config['SQLALCHEMY_DATABASE_URI'] = 'postgresql://user:pass@localhost/mydb'
    app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False

    db.init_app(app)

    with app.app_context():
        db.create_all()

    return app

Always set SQLALCHEMY_TRACK_MODIFICATIONS = False unless you specifically use Flask-SQLAlchemy's event system — leaving it unset triggers a deprecation warning and adds unnecessary memory overhead by tracking every object modification for signals you likely never listen for.

The db Object and Application Context

Because Flask-SQLAlchemy binds sessions to the current application context, any code touching db.session or db.create_all() must run inside an active app context — either implicitly during a request or explicitly via with app.app_context(): in scripts, CLI commands, or the interactive shell. This is why flask shell automatically pushes an app context, and why standalone scripts that import your models will raise RuntimeError: No application context if you forget the with block.

🏏

Cricket analogy: It is like needing an active match session before the third umpire can review a run-out — you can't invoke DRS outside the context of a live game.

Working with the Session

db.session is a SQLAlchemy scoped session that acts as a staging area, or unit of work: calling db.session.add(obj) stages a new or modified object, but nothing hits the database until db.session.commit() runs, which wraps the pending changes in a transaction and flushes them. db.session.rollback() discards staged changes on error, which is essential in a try/except around risky operations, and Flask-SQLAlchemy automatically removes the session at the end of each request via a teardown handler, so you rarely need to call db.session.remove() yourself inside request-handling code.

🏏

Cricket analogy: It is like a batter's runs not counting on the scoreboard until the umpire signals at the end of the over — add() is the shot played, commit() is the official signal.

Forgetting db.session.commit() is a common beginner bug: your object appears correctly set in memory during the request, but nothing was ever written to the database, so a subsequent request (or even the same request re-querying by a fresh session) won't find it. Always pair add() with an eventual commit(), and wrap risky multi-step operations in try/except with an explicit rollback() on failure to avoid leaving the session in a broken state.

  • Flask-SQLAlchemy wraps SQLAlchemy's ORM and Core, exposing everything through a single db object.
  • Configure the database via app.config['SQLALCHEMY_DATABASE_URI'] before calling db.init_app(app).
  • Use the application-factory pattern: create db = SQLAlchemy() at module level, bind it later with init_app.
  • Set SQLALCHEMY_TRACK_MODIFICATIONS = False to silence warnings and avoid unnecessary overhead.
  • All db.session and db.create_all() calls require an active application context.
  • db.session.add() stages changes; db.session.commit() writes them to the database as a transaction.
  • Use db.session.rollback() on errors to discard staged changes and keep the session healthy.

Practice what you learned

Was this page helpful?

Topics covered

#Python#FlaskStudyNotes#WebDevelopment#FlaskSQLAlchemyBasics#Flask#SQLAlchemy#Installing#Configuring#StudyNotes#SkillVeris