Isolation Levels: The Database Setting You're Probably Getting Wrong
Four levels, a spectrum of anomalies, and a default that isn't the one you think.

Search for a command to run...
Four levels, a spectrum of anomalies, and a default that isn't the one you think.

No comments yet. Be the first to comment.
Why "human in the loop" quietly turns into a reflex, and what a reliable system actually trains out of you

The industry didn't ask. It just stopped waiting.

The Company Building AI-Powered Job Displacement Has Thoughts on How to Handle AI-Powered Job Displacement

Google's TurboQuant Cuts LLM Memory by 6x — With Zero Accuracy Loss

Anthropic's Mythos Is Too Dangerous to Release. That Tells You Everything.

Transaction isolation levels are one of those topics every backend engineer nods along to and quietly hopes not to be quizzed on. They surface when concurrency bites — two transactions touching the same data at once — and the isolation level is the dial that decides how much each is allowed to see of the other's half-finished work. Get it wrong and you get bugs that only show up under load and are miserable to reproduce.
When transactions run concurrently, they step on each other in specific, named ways. One reads data another hasn't committed, which then rolls back — you just read something that never officially happened (a dirty read). You read a row twice in one transaction and get different values because someone changed it in between (a non-repeatable read). You run the same query twice and get a different set of rows because someone inserted one (a phantom read). Isolation levels are the database's menu of how many of these anomalies you'll tolerate in exchange for concurrency.
The SQL standard defines four, loosest to strictest. Read uncommitted lets you see other transactions' uncommitted changes — fast, and almost always a bad idea. Read committed only shows committed data, killing dirty reads; it's the sane baseline. Repeatable read guarantees rows you've already read won't change under you for the life of the transaction. Serializable is strictest — transactions behave as if they ran one after another, no anomalies at all — and you pay for that in performance and contention.
Each step up removes a class of anomaly and adds cost. That's the whole trade-off.
Two things, and they're where the real bugs live.
First, the default isn't universal, and it usually isn't what you'd guess. Postgres defaults to read committed; MySQL's InnoDB defaults to repeatable read. So the exact same application code can behave differently depending on the database underneath it — and a startling number of subtle bugs come from an engineer assuming a stronger, or weaker, guarantee than they're actually running under. If you've never checked your isolation level, you're trusting a default you didn't choose.
Second, the SQL standard is a loose guide, not a precise contract. Databases implement these levels with real differences behind the same names. Postgres only implements three distinct levels internally — ask for read uncommitted and you quietly get read committed. Its "repeatable read" is really snapshot isolation. And serializable isn't even the same mechanism between engines: Postgres uses an optimistic approach that lets transactions run and aborts the ones that would have conflicted, while MySQL leans on pessimistic locking — gap and next-key locks — to stop the conflict happening in the first place. Same word on the tin, genuinely different behaviour. The label tells you the intent; your database's docs tell you the truth.
Most applications live happily on read committed and reach for something stronger only where correctness genuinely demands it — money movements, inventory counts, anything where a phantom or a lost update is a real-world problem rather than a theoretical one. Don't crank everything to serializable out of caution; you'll trade throughput for a guarantee you mostly didn't need, and under Postgres you'll trade it for transactions that occasionally abort and have to be retried. But don't ignore the setting either, because the day concurrency bites, this is the dial you'll wish you'd understood a week earlier.
Isolation levels aren't academic trivia. They're the knob between "correct" and "fast," and the engineer who knows where theirs is set is the one who isn't debugging a heisenbug in production at midnight.