Most lists of lightweight databases rank them by install size, and install size is the least important thing about a database you have to run. The weight that matters is operational: how many processes it adds, how much of your attention it needs on a bad day, and how much work it takes to move the data somewhere else. Measured that way, the lightest option for a single-file side project and the lightest option for a small production service are frequently not the same thing.
SQLite is usually the right answer to the first and often the wrong answer to the second, and the reason why is worth understanding properly rather than as a rule of thumb.
Table of contents
- Two meanings of lightweight, and only one matters
- SQLite is genuinely light, until there are two of you
- The concurrency ceiling, honestly
- What a small managed Postgres or MySQL actually costs to run
- The middle ground people forget
- A decision that takes about a minute
- How this fits the rest of the stack
- FAQ
Two meanings of lightweight, and only one matters
When people search for a lightweight database they are usually describing one of two constraints, and the two point in opposite directions.
Resource weight. The database must run in very little memory, on a small machine, next to the application. This is a genuine constraint on embedded devices, on a $4 instance, or inside a container you would like to keep small.
Operational weight. The database must not require ongoing care. No patching schedule, no backup strategy to design, no separate thing to monitor, no second component that can be down while the first is up.
Almost everybody who says lightweight means the second one and describes the first, because resource usage is the number that appears on a comparison page. It is worth being honest with yourself about which you actually mean, because the answers diverge as soon as more than one process needs the data.
SQLite is genuinely light, until there are two of you
SQLite deserves its reputation. It is a library, not a server. There is no port, no daemon, no user management and no connection string — the database is a file, and the application opens it.
For a very large class of applications this is not a compromise, it is simply better. A read-heavy site, a desktop application, a CLI tool, a test suite, an embedded system, a single-process service that handles a few hundred requests a second: all of these are well served by SQLite, and reaching for a database server instead adds a component for no benefit.
The constraint is architectural rather than about scale. SQLite lives on a filesystem, and the application must be on the same filesystem. That means:
- One machine. Two application instances behind a load balancer cannot both open the same SQLite file safely unless they share a filesystem, and network filesystems have a long history of breaking exactly the locking guarantees SQLite depends on.
- Your deployment must have persistent disk. Plenty of modern hosting gives containers an ephemeral filesystem that is wiped on redeploy, which turns your database into a cache with an unusually confident name.
- Scaling means scaling up, not out.
The concurrency ceiling, honestly
SQLite handles concurrent reads well. Concurrent writes are the limit, because a write takes a lock over the whole database rather than a row or a page.
In write-ahead logging mode — which you should turn on, and which is not the default — readers do not block writers and writers do not block readers. But there is still only one writer at a time. If your workload is one write every few seconds it will never notice. If it is a queue being drained by four workers, it will notice immediately, and the symptom is a database-is-locked error under load.
The practical settings that make SQLite behave well in a server context are few and worth knowing:
PRAGMA journal_mode = WAL;
PRAGMA synchronous = NORMAL;
PRAGMA busy_timeout = 5000;
PRAGMA foreign_keys = ON;
The busy timeout is the one people miss. Without it, a concurrent write fails instantly instead of waiting a moment for the lock, and a large share of the SQLite-does-not-work-for-us stories are that default.
What a small managed Postgres or MySQL actually costs to run
Here is the part the comparison lists get wrong. They price a database server as though you are going to install, patch and back it up yourself, which is genuinely heavy work. But a small managed instance is not that. It is a connection string.
Measured in operational weight, a managed Postgres on a small plan involves: no installation, no patching, backups on a schedule you did not have to design, and a defined connection limit. Compared with SQLite on a machine you are also responsible for backing up, it is arguably the lighter option, because the backup problem is solved rather than delegated to a cron job you wrote once and have not checked since.
The cost is real but small at this size — the general plan ladder starts at $4 for a Dev instance and $6 for Basic, and there is a free tier of 15 days a month before it moves to $1.80. That is genuinely a different order of magnitude from the operational cost of losing a file-based database because the volume was ephemeral.
So the honest framing is not SQLite versus a real database. It is: does anything other than one process need this data, now or plausibly soon?
The middle ground people forget
There are two shapes that get overlooked and both are worth knowing.
SQLite with a real persistent volume and a replication sidecar. Streaming SQLite’s write-ahead log to object storage gives you continuous backup and point-in-time restore for a file database, which removes the single biggest objection to using one in production. It is still one machine, but it is one machine you can rebuild.
An analytical file database. For workloads that are mostly aggregation over columns rather than transactions over rows — reporting, dashboards, log crunching — a columnar embedded engine will outperform both SQLite and a small Postgres by a wide margin on the same hardware, while remaining a single file. Wrong tool for a web application’s user table, excellent for the reporting query that was timing out.
Both of these are lighter than they look, and both are more capable than the usual embedded-versus-server framing allows for.
A decision that takes about a minute
Run through it in order and stop at the first yes:
- Will more than one process or machine write to this data? Use a database server. This is the only question that genuinely settles it, and everything else is preference.
- Is the filesystem ephemeral? Use a database server, or attach a persistent volume first. A file database on a disk that disappears on redeploy is a bug waiting for a deployment.
- Is this analytical rather than transactional? Consider a columnar embedded engine before either.
- Is it one process, on a disk that persists, doing mostly reads? Use SQLite, turn on write-ahead logging, set a busy timeout, and get on with the actual work.
The common mistake is not picking wrong at step four. It is picking SQLite at step four, succeeding, and then adding a second application instance eighteen months later without revisiting the decision.
How this fits the rest of the stack
The reason this decision feels heavier than it is comes down to cost anxiety — the sense that adding a database instance turns a cheap project into an expensive one. It usually does not, and the way to check is to look at the line items rather than guess: the RunxBuild hosting calculator prices the service, the database, the storage and the bandwidth separately, so you can see what adding a managed instance actually changes.
RunxBuild offers managed MySQL and Postgres with backups, connection limits and private networking handled, and persistent storage that attaches to a service if what you want is SQLite on a volume that survives a redeploy. Both are legitimate answers. The one that is not legitimate is a file database on an ephemeral disk, which is the failure this whole question exists to avoid.
Useful related references:
- SQLite vs PostgreSQL: which one your project needs
- The fastest database, and why the question is usually wrong
- What database pricing actually includes
- Databases on RunxBuild
- Persistent storage for services
FAQ
What is the most lightweight database?
By resource usage, SQLite, because it is a library rather than a server and adds no process at all. By operational weight, a small managed Postgres or MySQL can be lighter, since patching and backups are handled for you rather than becoming your responsibility.
Is SQLite good enough for production?
For a single-process application on persistent disk, frequently yes, and it is used that way at serious scale. The limits are architectural rather than about volume: one writer at a time, and one filesystem, which rules out running several application instances against the same database.
When should I move from SQLite to Postgres?
When a second process or machine needs to write, when your filesystem is ephemeral, or when concurrent writes start producing locked-database errors that a busy timeout does not absorb. Read volume alone is rarely the reason.
Does SQLite handle concurrent writes?
One writer at a time. With write-ahead logging enabled, readers and writers do not block each other, but writes are still serialised. Setting a busy timeout so a blocked write waits rather than failing immediately fixes most of the problems people attribute to SQLite concurrency.
Is a lightweight database cheaper to run?
Not necessarily. An embedded database has no instance cost but does need persistent disk and a backup process you build yourself. A small managed instance has a monthly price and removes that work. Which is cheaper depends on what your time is worth.