SQLite in production, honestly
It is a real option for real applications now — with one constraint that decides your entire deployment shape.
SQLite has moved from "development only" to a defensible production choice, and Rails 8 leans into it deliberately. It is worth understanding what actually changed and what did not.
The constraint that shapes everything
SQLite allows one writer at a time. Not one per table — one per database.
That single fact determines your deployment. Multiple processes do not increase write capacity; they increase contention for the same lock. The conventional Rails advice — workers equal to CPU cores — is actively wrong here.
A single process with a modest thread pool is usually the right shape. It feels under-provisioned by habit and is correct for the storage engine underneath.
Reads are a different story: they are concurrent and extremely fast, because there is no network hop at all. For read-heavy applications, which is most content-shaped software, this trade is very favourable.
WAL is not optional
Write-Ahead Logging changes the concurrency story enough that it should be considered mandatory. Without it, readers and writers block each other. With it, readers continue during a write and only writers serialise.
A sensible busy timeout matters too, so that a query waiting for the write lock waits briefly rather than failing immediately. Rails 8's defaults handle much of this, but it is worth confirming rather than assuming.
The operational trade
What you gain is enormous simplicity: no separate database server, no connection pool arithmetic, no network latency on every query, no credentials to rotate. Backups are a file copy. Local development is identical to production.
What you give up is horizontal scaling of writes and the ability to detach storage from compute. Your application server and your database are the same machine, which means the disk must be persistent — on a platform with an ephemeral filesystem, every deploy wipes the database unless you mount a volume deliberately.
That last point catches people. The application boots fine. The data is simply gone.
One writer, persistent disk. Those two facts decide whether SQLite fits before any benchmark does.
When to choose it
It fits read-heavy applications, content sites, internal tools, and anything where a single machine has ample headroom. It fits especially well where operational simplicity is worth more than theoretical scale.
It does not fit write-heavy workloads, anything needing multiple application servers against one dataset, or teams that need the database to outlive individual instances.
The honest version is that most applications never reach the point where it matters, and a great many teams carry the complexity of a separate database for scale they will not need. Knowing which you are is worth more than the default.