Solving SQLite Concurrency Bottlenecks with Write-Ahead Logging (WAL)
Stop fighting 'database is locked' errors in SQLite. Learn how Write-Ahead Logging (WAL) enables concurrent reads and writes to boost application performance.
05 Dec 2025, 09:48 UTC

The 'Database is Locked' Problem
In a default SQLite configuration, the database uses a rollback journal. This means that when a process wants to write to the database, it acquires an exclusive lock. While that write is happening, no other process can read from the database. Conversely, if a long-running read operation is active, a writer must wait until the reader finishes. For applications with a high volume of concurrent users, this leads to the dreaded SQLITE_BUSY error: "database is locked".
The solution for most read-heavy applications is to switch from the default journal mode to Write-Ahead Logging (WAL). WAL changes the fundamental locking mechanism, allowing readers to coexist with a writer without blocking each other.
How WAL Changes the Data Flow
In standard rollback mode, SQLite writes changes directly to the main database file. To ensure safety, it keeps a copy of the original data in a journal file so it can undo changes if a crash occurs. This requires exclusive access to the main file.
WAL flips this logic. Instead of modifying the main database file immediately, SQLite appends changes to a separate file called the -wal file. Because the main database file remains untouched during the write process, readers can continue to access the original data from the main file while the writer adds new data to the WAL file. This creates a non-blocking environment where readers and writers operate in parallel.
The Role of the Checkpoint
Since changes are stored in the WAL file, the main database file eventually becomes outdated. SQLite uses a process called checkpointing to move the transactions from the WAL file back into the main database file. This typically happens automatically when the WAL file reaches a certain size (usually 1,000 pages), but it can also be triggered manually.
Implementation and Verification
Enabling WAL mode is a persistent change to the database file. Once set, you do not need to run the command every time you connect to the database.
Enabling WAL Mode
Run the following command using the SQLite CLI or through your application's database driver. This must be executed with write permissions to the directory containing the database file.
-- Run this in the SQLite CLI or via your app's execute method
PRAGMA journal_mode=WAL;
Verifying the Change
To confirm the mode has been updated, query the current journal mode:
PRAGMA journal_mode;
The expected output should be wal. Additionally, you can check your filesystem. When a connection is active in WAL mode, you will see two auxiliary files alongside your example.db file: example.db-wal and example.db-shm. The -shm file is a shared-memory file used to coordinate access between the different processes.
Trade-offs and Limitations
WAL mode is not a universal silver bullet. There are three primary constraints to consider before deploying it:
- Networked Filesystems: WAL mode requires shared memory for coordination. Because of how locking is handled, it is not supported on networked filesystems like NFS or SMB. If your database resides on a network drive, stick to the default rollback journal.
- Read Performance Degradation: If a checkpoint does not occur frequently, the WAL file can grow very large. Since a reader must check both the main database and the WAL file to find the most recent version of a page, a massive WAL file can slow down read queries.
- File Management: Your deployment scripts must account for the
-waland-shmfiles. If you back up the database by simply copying the.dbfile while a process is writing to the WAL, your backup may be corrupted or inconsistent.
Practical Decision Matrix
| Scenario | Recommended Mode | Reasoning |
|---|---|---|
| Single-user local tool | DELETE (Default) | Simpler file management; concurrency is not a factor. |
| Web app with many readers | WAL | Prevents readers from blocking writers and vice versa. |
| Database on a NAS/NFS share | DELETE (Default) | WAL is incompatible with network file locking. |
| High-frequency write bursts | WAL | Reduces disk fsync overhead by appending to a log. |
Closing Action
If your application is throwing "database is locked" errors during concurrent access, test WAL mode in a staging environment. Enable it via PRAGMA journal_mode=WAL;, verify the creation of the -shm file, and monitor the size of the -wal file under load to ensure your checkpointing is keeping pace with your write volume.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.