Back SQLAlchemy - FASTAPI- Big Picture Flow 25 Jun, 2026

Yes. Your understanding is already quite good. The only missing piece is why each object exists and how they all connect together.

Think of it as building a house before people start living in it.


BIG PICTURE

                Step 1
        Tell Python where database is

DATABASE_URL
      │
      ▼
sqlite:///./users.db

                Step 2
      Build connection engine

create_engine()

      │
      ▼
engine

                Step 3
      Build session factory

sessionmaker(bind=engine)

      │
      ▼
SessionLocal

                Step 4
    Create ORM Base class

Base = declarative_base()

      │
      ▼

class User(Base)

      │
      ▼

Table Definition

                Step 5
Tell SQLAlchemy to create tables

Base.metadata.create_all(bind=engine)

      │
      ▼

users.db
      │
      ▼

users Table

                Step 6
Whenever request comes

db = SessionLocal()

      │
      ▼

Read / Write Database

Notice that Steps 1–5 happen only once (during application startup), while Step 6 happens for every request.


STEP 1 — Database URL

DATABASE_URL = "sqlite:///./users.db"

This is simply the database's address.

Imagine you're telling a delivery person:

"My house is at 25 Green Street."

Similarly:

sqlite:///./users.db

means

My database is stored in the file users.db.

Nothing is created yet.

You're only specifying where the database is located.


STEP 2 — Create Engine

engine = create_engine(DATABASE_URL)

The engine is not the database.

It is a connection manager.

Think of it like this:

Python
   │
   ▼
Engine
   │
   ▼
users.db

The engine knows:

  • where the database is

  • how to connect

  • how to send SQL

  • how to receive results

Without the engine,

Python cannot talk to SQLite.


Real-life analogy

Imagine your database is another country.

The engine is the airplane.

Without the airplane,

you cannot travel there.


STEP 3 — Session Factory

SessionLocal = sessionmaker(bind=engine)

This is one of the biggest concepts beginners struggle with.

Notice carefully:

This does NOT create a database session.

It creates a factory that knows how to create sessions.

Think of a cookie factory.

Cookie Factory

      │

Makes Cookies

Similarly,

Session Factory

      │

Makes Sessions

So

SessionLocal

is NOT a session.

It is a machine that creates sessions.


Later,

db = SessionLocal()

creates an actual session.

Exactly like

CookieFactory()

↓

Cookie

STEP 4 — Create Base

Base = declarative_base()

This tells SQLAlchemy:

"Every class inheriting from Base is a database table."

Without Base,

class User:

is just a normal Python class.

With Base,

class User(Base):

SQLAlchemy immediately understands:

This represents a database table.


STEP 5 — Define Table

class User(Base):

Now you describe the table.

__tablename__ = "users"

means

Database table name:

users

Then

id = Column(...)

means

id column

Then

username = Column(...)

means

username column

Then

hashed_password = Column(...)

means

hashed_password column

At this point,

the table still doesn't exist.

You're only describing it.

Think of drawing a house blueprint.

The house hasn't been built yet.


STEP 6 — Create Tables

Base.metadata.create_all(bind=engine)

This is where SQLAlchemy says

"Okay, I've seen all the blueprints."

Now it asks:

Does users table exist?

If NO,

it creates it.

If YES,

it skips it.

Equivalent SQL:

CREATE TABLE users(
id INTEGER PRIMARY KEY,
username TEXT,
hashed_password TEXT
);

Now your database becomes

users.db

│

└── users table

IMPORTANT

Notice something.

Until now,

no user exists.

Only the table exists.

users

-----------------------

(empty)

STEP 7 — Request Comes

Suppose someone signs up.

FastAPI calls

get_db()

Inside

db = SessionLocal()

Remember?

SessionLocal is the factory.

Session Factory

↓

Creates Session

Now

db

is your active conversation with the database.


Imagine

Python

│

db

│

Engine

│

users.db

STEP 8 — Add User

new_user = User(...)

creates a Python object.

Not a database row.

Just a Python object.

Memory

↓

User Object

Then

db.add(new_user)

tells SQLAlchemy

"Prepare to insert this."

Still not saved.


Then

db.commit()

actually writes it into

users.db

STEP 9 — Close Session

Finally,

db.close()

ends the conversation.

Exactly like hanging up a phone call.


Why do we need get_db()?

Instead of writing

db = SessionLocal()

everywhere,

we create one reusable function.

def get_db():
    db = SessionLocal()
    try:
        yield db
    finally:
        db.close()

Every request gets:

Open Session

↓

Use Database

↓

Close Session

Automatically.


Complete Lifecycle

Developer Starts FastAPI

        │

        ▼

DATABASE_URL

        │

        ▼

create_engine()

        │

        ▼

engine

        │

        ▼

sessionmaker()

        │

        ▼

SessionLocal (Factory)

        │

        ▼

declarative_base()

        │

        ▼

class User(Base)

        │

        ▼

create_all()

        │

        ▼

users.db

        │

        ▼

users table created

═══════════════════════════════════════

User sends Signup Request

        │

        ▼

get_db()

        │

        ▼

db = SessionLocal()

        │

        ▼

Create User Object

        │

        ▼

db.add()

        │

        ▼

db.commit()

        │

        ▼

Row Stored in users.db

        │

        ▼

db.close()

The key mental model

There are three different layers, and keeping them separate removes most confusion:

  • Database configuration (created once): DATABASE_URLengineSessionLocal

  • Database schema (created once): BaseUser model → Base.metadata.create_all(bind=engine)

  • Database operations (every request): db = SessionLocal() → query/add/update/delete → db.commit() (if needed) → db.close()

Once you see these as Configuration → Schema → Runtime Operations, the entire SQLAlchemy workflow becomes much easier to reason about.

Rate This Note
Login to Rate This Note