SQLAlchemy What's the difference between flush and commit?
System Design practice on Codemia
Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.
Introduction
In SQLAlchemy, flush() and commit() are related, but they do different jobs. flush() sends pending SQL changes from the session to the database inside the current transaction, while commit() finalizes that transaction and makes the changes durable.
The easiest way to remember the difference is this: flush writes now, commit finishes now. A flush can still be rolled back. A commit ends the transaction.
What flush() Does
The ORM session keeps track of pending inserts, updates, and deletes in memory. When you call flush(), SQLAlchemy emits the necessary SQL so the database state inside the current transaction matches the in-memory objects.
That means flush() can:
- execute
INSERT,UPDATE, andDELETE - populate database-generated primary keys
- trigger database constraints before commit
- make later ORM queries in the same session consistent with pending work
Here is a minimal example:
Before the flush, user.id is usually None. After the flush, SQLAlchemy has already executed the INSERT, so the generated primary key is available.
What commit() Does
commit() ends the current transaction. In SQLAlchemy, that includes an automatic flush first if there are pending changes.
So this sequence:
behaves roughly like this:
The important difference is durability and visibility. After commit, the transaction is complete. Other database sessions can now observe the committed changes according to the database isolation rules.
Visibility: Same Session vs Other Sessions
A flushed row is usually visible to the current session because it is part of that session's ongoing transaction. It is not necessarily visible to another session until commit.
This example demonstrates the difference:
The first session sees the row after flush because it is part of its own transaction. The second session does not reliably see it until the first session commits.
Why Manual Flush Is Useful
Even though commit() performs a flush automatically, explicit flush() calls are still useful.
Common reasons:
- you need a generated primary key before commit
- you want database constraint failures to happen early
- you are building related objects and need foreign keys now
- you want to send SQL but keep the transaction open for more work
For example:
That pattern is very common in service code.
Autoflush Is Related, but Not the Same
SQLAlchemy also has autoflush, which means the session may flush automatically before certain queries so query results stay consistent with pending changes.
That does not mean every operation commits. Autoflush still happens inside the current transaction.
You can disable it temporarily if needed:
But disabling autoflush should be deliberate. It is usually there to prevent subtle read-after-write inconsistencies within the session.
Common Pitfalls
The most common mistake is thinking flush() permanently saves data. It does not. A later rollback can still undo flushed work.
Another mistake is thinking commit() only commits and never flushes. In practice, commit() performs a flush first when needed.
People also get confused when primary keys appear before commit. That is normal because a flush may already have inserted the row.
Finally, if a flush fails because of a constraint violation, the session is no longer in a clean transaction state. You usually need to call rollback() before continuing to use that session.
Summary
- '
flush()sends pending SQL to the database inside the current transaction.' - '
commit()finalizes the transaction and makes the changes durable.' - A flush can still be rolled back.
- '
commit()normally performs a flush automatically first.' - Manual flush is useful when you need generated keys or early constraint checks.
- Flushed changes are usually visible in the same session before they are visible to other sessions.
Related reading
- sqlalchemy.exc.NoSuchModuleError Can't load plugin sqlalchemy.dialectspostgres
- SqlCommand Close and Dispose - which to call?
- SqlDataAdapter vs SqlDataReader
- SqlDataAdapter.Fill - Asynchronous approach
- sqlite3.ProgrammingError Incorrect number of bindings supplied. The current statement uses 1, and there are 74 supplied
- SSL InsecurePlatform error when using Requests package
- Squash the first two commits in Git?
- SSL certificate rejected trying to access GitHub over HTTPS behind firewall

System Design Fundamentals
Build a strong foundation in designing scalable, reliable distributed systems.
View the courseTrack what you have practised
A free account saves your progress, solutions and study plan across every problem on Codemia.
System Design practice on Codemia
Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.