WAL mode is a setting that changes how SQLite saves changes: instead of overwriting the database file directly, it appends them to a separate write-ahead log file and merges them into the database later. The practical result is that reading and writing can happen at the same time, which removes most "database is locked" errors between readers and a writer. Use it for almost any application where more than one connection touches the database and the file is on a local disk. Do not use it on a network filesystem.
What a journal mode is
SQLite guarantees that a transaction either happens completely or not at all, even if the program crashes or the power fails halfway through. To keep that promise it needs a second file where it can keep enough information to recover. The journal mode decides what that second file contains.
There are two approaches.
Rollback journal (the default, called DELETE mode). Before SQLite changes a page of the database, it copies the original page into a file named yourdb-journal. Then it writes the new content into the database file. Deleting the journal is the commit. If something goes wrong first, the saved pages are copied back.
Write-ahead log. SQLite leaves the database file alone and appends the changed pages to a file named yourdb-wal. Writing a commit record to that file is the commit. Later, a step called a checkpoint copies the accumulated changes into the database file.
One saves the old data and overwrites the database. The other saves the new data and leaves the database untouched for now. Everything else follows from that difference.
Rollback journal and WAL compared
Rollback journal (DELETE)
WAL
Where a change is written first
The original page goes to -journal, then the database file is overwritten
Why Python raises "database is locked", how timeout, isolation_level and autocommit interact, and the working pattern for threads, worker processes, SQLAlchemy, Django and aiosqlite.
-wal and -shm, for as long as the database is open
Works on a network filesystem
Yes, where the filesystem's file locking is reliable
No
Atomic commit across several attached databases
Yes
No, each database commits separately
Extra maintenance step
None
Checkpoints, automatic by default
Default
Yes
No, you turn it on
What you gain
Readers and the writer stop blocking each other. This is the main reason to use WAL. In rollback-journal mode a writer has to wait until nobody is reading before it can commit, and nobody can read while it commits. A slow report can stall every write, and a write can make page loads fail. In WAL mode a reader sees the database as it was when its query began and is not affected by writes that happen meanwhile.
You can see the difference with two terminals and the sqlite3 shell. First create a small database:
-- sqlite3 demo.dbCREATE TABLE notes (id INTEGERPRIMARY KEY, body TEXT);
INSERT INTO notes (body) VALUES ('first');
Then, in terminal 1, start reading and leave the transaction open:
BEGIN;
SELECT*FROM notes;
In terminal 2, try to write:
INSERT INTO notes (body) VALUES ('second');
-- rollback-journal mode: fails with "database is locked"-- WAL mode: succeeds
Type COMMIT; in terminal 1 to end its transaction. To repeat the test in the other mode, quit both shells, open one, run PRAGMA journal_mode = WAL;, and start again.
Writes are usually faster. A rollback-journal commit writes each changed page twice, once to the journal and once to the database, at scattered positions in the file. A WAL commit writes each page once, one after another at the end of the log.
Fewer sync operations. Forcing data to disk is the slowest part of a commit. WAL needs fewer of these, and with the synchronous = NORMAL setting it only syncs during checkpoints.
SQLite's own documentation says WAL is significantly faster in most scenarios. How much depends on your storage and workload, so measure with your own data if the number matters.
What it costs
These are the disadvantages listed in the SQLite documentation, in plain terms.
Every process must be on the same machine. WAL coordinates connections through a small region of shared memory, which is backed by the -shm file. Processes on different computers cannot share memory.
Two extra files.yourdb-wal and yourdb-shm sit next to the database while it is open. The -wal file holds real data. If you copy or move the database while it is in use, the WAL must go with it.
Checkpoints exist. They run automatically, so you can ignore them at first. In a busy application they need some attention, because a reader that never finishes can stop them from completing and let the -wal file grow.
No atomic commit across attached databases. If one transaction changes two databases joined with ATTACH, each is committed safely on its own, but a crash at the wrong moment can leave one updated and the other not.
Slightly slower when nearly everything is a read. The documentation estimates 1% or 2% for applications that mostly read and seldom write.
The page size is fixed while in WAL mode. To change it you must switch back to a rollback mode first.
When you should not use it
The database is on a network filesystem such as NFS or SMB, or several machines open the same file. This is the firm rule. WAL does not work across hosts.
The platform has no shared memory. Some unusual or embedded environments use a storage layer without it. Turning WAL on fails there, and the database stays in its previous mode. (There is a workaround for a single process, exclusive locking mode, covered in the internals article linked below.)
You depend on one transaction updating several attached databases atomically.
The database will sit on read-only media, such as a disk image or a read-only mount. A WAL database can be read there only under certain conditions. SQLite's advice is to convert it to DELETE mode before putting it on read-only media.
The file is a document format that users copy, email or sync as a single file. The extra files are easy to lose. SQLite removes them when the last connection closes cleanly, but a copy taken while the application is open can miss data.
You run very large single transactions. A transaction that rewrites hundreds of megabytes produces a WAL of that size, and the WAL cannot be trimmed until the transaction ends. Since SQLite 3.11.0 WAL handles large transactions as efficiently as rollback mode, but the disk space is still needed. Split bulk loads into several transactions, or do them in rollback mode.
Only one connection ever uses the database. A single-user script gains no concurrency. WAL may still be faster for writes, but there is nothing wrong with the default.
If none of these apply and more than one thread or process opens the database, turn WAL on.
How to turn it on
Run one statement on any connection:
PRAGMA journal_mode = WAL;
The statement returns a row containing the mode now in effect. Check it. wal means it worked. Anything else, such as delete, means SQLite could not switch and left the database as it was.
Requirements: SQLite 3.7.0 or later (released in 2010, so nearly every installation qualifies) and a real file. An in-memory database cannot use WAL; the statement returns memory.
Two more settings usually go with it. Unlike the journal mode, these apply only to the connection that runs them, so set them each time you connect:
PRAGMA busy_timeout =5000; -- wait up to 5 seconds for a lock instead of failing at once
PRAGMA synchronous = NORMAL; -- optional: faster commits, see below
synchronous = NORMAL is the common pairing with WAL. The database cannot be corrupted by a crash or power failure in this configuration, but the last few transactions committed just before a power loss might be missing afterwards. If losing a committed transaction is never acceptable, leave synchronous at FULL.
The setting is persistent
The journal mode is recorded in the database file itself. Set it once and the database is in WAL mode for every connection, in every program and language, including after a restart. You do not need to run the pragma on each connection, though doing so is harmless.
This also means you can convert an existing application without changing its code: stop it, run the pragma once from the sqlite3 shell, start it again.
This is the exception among the journal modes. If you set another one, such as TRUNCATE, the database goes back to DELETE the next time it is opened. busy_timeout and synchronous are not stored in the file either.
To see what mode a database is in:
PRAGMA journal_mode;
How to switch back
PRAGMA journal_mode =DELETE;
This must be the only connection to the database. If any other connection has it open, the statement fails with "database is locked", so stop the application first. On success SQLite checkpoints the remaining changes into the database file and removes the -wal and -shm files, leaving a single self-contained file.
Switch back before you put a database on read-only media, hand it to someone as a single file, or move it to a machine with a very old SQLite.
Quick answers
Does WAL allow more than one writer at a time? No. SQLite permits one write transaction at a time in every mode. WAL removes the conflicts between readers and the writer, not between writers. A second writer waits for the first, for as long as its busy_timeout allows.
Can I delete the -wal and -shm files? Not by hand. The -wal file can contain committed transactions that are not in the main file yet, and deleting it loses them. Close every connection and SQLite removes both files itself.
Why are the files still there after my program exits? Either the program did not close its connection cleanly, another process still has the database open, or the last connection to close was a read-only one. The files are harmless. Opening and closing the database normally cleans them up. Some platform builds of SQLite, including the one that ships with macOS, keep them on purpose.
How big does the -wal file get? With default settings SQLite checkpoints once it reaches about 1000 pages, roughly 4 MB. It grows well beyond that only if checkpoints cannot finish.
Does WAL make reads faster? Not individually. What improves is that reads are no longer stopped by writes, and writes no longer wait for reads.
How do I back up a WAL database? Not by copying the main file while the application runs. Use the .backup command of the sqlite3 shell or VACUUM INTO, both of which produce a consistent copy from a live database.
Is it safe? Yes. WAL has been part of SQLite since version 3.7.0, and with synchronous = FULL transactions are fully durable. One thing to check is the SQLite version: a rare corruption bug in WAL mode was fixed in 3.51.3, so prefer a current release.
How the -wal and -shm files, read marks and checkpoints work, why a WAL grows without bound, and how to set checkpointing, journal_size_limit and synchronous.
An ordered procedure for SQLITE_BUSY with a verification for each step, a script that reproduces the contention, and the matching settings for Python, Node and Go drivers.