Turn on WAL mode before you blame SQLite
Every time someone tells me SQLite locks up under concurrent access, they are running it in the default rollback-journal mode. One pragma changes the story:
PRAGMA journal_mode = WAL;
Write-Ahead Logging lets readers keep reading while a writer is writing. In the default mode a write takes an exclusive lock over the whole database and every reader waits. With WAL, readers see a consistent snapshot and only writers serialize against each other. For a local app, a background job, or a low-to-moderate write service, that is the difference between “SQLite is fine” and “we need Postgres.”
It is a one-time setting stored in the database file, so you set it once at creation. I pair it with:
PRAGMA synchronous = NORMAL;
PRAGMA busy_timeout = 5000;
NORMAL is a safe durability tradeoff under WAL, and busy_timeout tells SQLite to wait for a lock instead of failing instantly. SQLite scales further than most people assume. The defaults are just conservative, and the defaults are usually what people benchmark.