# Introduction to SQLAlchemy

_SQLAlchemy is perhaps one of the most versatile and confusing ORM that is on the market, SQLAlchemy is tightly coupled with native SQL in many ways, which gives it both its high learning curve, as well as its flexibility._

By Yonatan Vega · September 24, 2025

> Source: https://fullstack.rocks/article/introduction-to-sqlalchemy

![A friendly wizard brewing a green portion in a couldron that says SQL on it](https://storage.googleapis.com/fullstack-rocks-media/poster-960-b388fef3a525.webp)

If you’ve ever worked on a Web service using python you’ve almost definitely heard of SQLAlchemy, maybe you’ve also attempted to use it, or already are using it, either way, that doesn’t make this Library any easier to use, this article series aims to shed some light on some of SQLAlchemy’s basic as well as the most complex / confusing subjects.

## What is an ORM?

For the uninitiated in ORMs, I think it’s best to begin with a definition, an ORM is quite simply an “Object-Relational Mapper”, which roughly translates to a library that takes a relational database, and maps it to objects.

> **Note:** 💡 For you NoSQL (document based) database users.
>
> A relational database is a database which defines its data structures mostly in advance using “tables”, the relationships, indexes and all definitions are mostly created before the application even starts up, deviation from the defined structures and rules that you set on your database will result in errors.
>
> If for the sake of example we would compare MongoDB and PostgreSQL, we could say that MongoDB’s more lax data structures could be compared to a scripting language that doesn’t force the use of type checks, while PostgreSQL might be compared to a strictly typed language that would not compile unless all of the rules of the program are satisfied.
>
> This comparison does not mean that one of these options is better than the other, as with anything we must consider the task at hand when choosing our development stack.

This kind library allows us to define our database layer models, into application layer objects, this in theory should make the life of a developer much easier, since instantiation of objects and accessing data through them should be easier than working with the database directly.

In practice, an ORM is not going to make your life easier if you do not understand your database or the ORM that you are using, while most ORMs implement the basics to database interaction in the same way, once we delve deeper into more complex queries and operations, these ORMs become much more opinionated.

## SQLAlchemy’s complexities

So if ORMs are opinionated, what makes SQLAlchemy complex?

Well, making basic queries in SQLAlchemy is pretty simple, the syntax can probably be read by any Python developer who can also read even basic SQL.

For example:

```python
users = session.query(User).filter(User.name == 'Jonathan').all()
```

And yet, at the same time you could also write

```python
users = session.execute(select(User).where(User.name == 'Jonathan')).all()
```

And these two example are not even the only two ways!

In reality SQLAlchemy’s opinion is that you should have the power to choose the level of abstraction you would like to put between yourself and your data.

would you like to work with nothing but python models, doing all of your CRUD operations without anything that looks remotely like SQL? You got it.

on the other hand you could write all of your queries using a syntax that closely resembles SQL, even advanced SQL queries such as CTEs, subqueries and database functions can be clearly represented using SQLAlchemy.

In reality you should probably find a place in the middle, between complete abstraction and a total mirror of your database, there exists a sweet spot where you may easily interact with your database entities while being able to use your creative muscles for more complex tasks.

## ORM’s vs. Plain SQL Queries

For any developer comfortable with SQL who begins to use an ORM there comes a moment of hesitation, why should I use an ORM? If I know how to use SQL, and I’m comfortable with navigating my database, wouldn’t an ORM just slow me down?

Well… yes, and no.

Just like learning a new framework or library, there are always rough beginnings, reading the documentation is mandatory, and attempting anything out of the ordinary requires some sleeve rolling and key mashing.

For you more experienced SQL users, you might also be wondering about the performance of ORMs compared to native SQL, well, most of the time, performance should be pretty much the same, for the simple queries such as straightforward CRUD operations, even when adding some joins or subqueries into the mix, SQLAlchemy’s SQL statements seem pretty well optimized, does it mean that at any point in time SQLAlchemy’s performance is on par with native SQL?

No.

If your relationships are poorly optimized and you rely on SQLAlchemy to magically make the best decisions for you, you might as well write poorly optimized SQL code.

#### But at the same time

One thing to consider is development performance, while application performance is important to consider, if 90% of your queries are straightforward and efficient while 10% of your queries are complex and prone to pit-falls, you will still save a lot of time writing your straightforward code, while working hard on 10% of your queries.

Is that worth the time wasted on debugging application performance 10% of the time? Probably. ORMs make it easier to onboard developers and deliver code faster, which is one of the main reasons we choose to use any library or framework.

## Database Abstraction

Some level of abstraction is always good, abstraction is one of the most widely used design patterns out there, either on low level code and high level code.

Abstracting a database is a good idea in most medium to large scale applications, can you really expect every developer on your team to memorize the names of each database table that is in for your application?

At the same time there are times where it makes sense to keep operations in the database, if I have to iterate and validate a value for each entry in a large database table, does it make sense to load all of these rows into memory, operate on them and push them back into the database? Probably not, for this it makes more sense to have a function or procedure in the database that does this for us, thankfully database functions are actually also supported with SQLAlchemy, as a mild level of abstraction for database operations.
