- SQLite was never competing with server databases
- When many users share the data
- When reports and analytics are the problem
- When you're in the Java world
- When you'll ship the database inside a product
- When the problem is distribution, or SQL itself
- All seven side by side
- Matching the move to your app
- What changes in your code
- Checks before you migrate a single table
- Frequently asked questions
Leave only when the database itself is the bottleneck: lots of simultaneous writers, access over a network from several machines, or heavy analytical queries. Shared multi-user apps suit a client/server relational database. Reporting on local files suits an embedded analytical engine. Per-user databases suit a cloud service built on the same engine. If you don't need SQL at all, a key-value store fits.
SQLite is a library that lives inside your program and gives you a transactional SQL engine with no server and nothing to configure. Its source is in the public domain, and an entire database, from tables to triggers, sits in one file on disk. Developers usually start looking around when an app grows: more users writing at once, a second server that needs the same data, or reports that crawl.
The seven options below are grouped by which of those limits they address.
SQLite was never competing with server databases
SQLite's documentation says so plainly. It says it isn't directly comparable to client/server products such as MySQL, Oracle, PostgreSQL or SQL Server, and that its real competitor is fopen(), the ordinary way a program opens a file. Server databases, it says, put scalability, concurrency, centralisation and control first, while it puts economy, efficiency, reliability, independence and simplicity first.
So most so-called replacements solve a different problem. Swap it for a server database and you're signing up for a server: something to install, secure, back up and keep running. That's the right trade when many users share data, and the wrong one for a desktop app or a phone.
One entry below doesn't replace it at all. Turso says it's built on SQLite, so choosing it means keeping the engine and changing how the data is spread out. That's a very different move from switching engines.
A quick self-check: if one application owns the data, writes come in one at a time, and nobody else needs to reach it across a network, SQLite is probably still the best tool you've got. Slow queries are often an index problem rather than an engine problem, so look at the query plan before you look at a new database.
The same goes for size. A large file isn't a reason to leave on its own; a large file that several servers must write to at once is.
And if the only complaint is that reports are slow, you may not need to replace anything. You can keep SQLite for the app and add DuckDB beside it for reporting, which leaves the working system untouched.
When many users share the data
Pick from this pair when several machines must write to one shared store. You gain a central server and give up the single file.
MariaDB
Built by the people who first wrote MySQL, and promised by MariaDB.org to remain open source. It began life as an improved drop-in stand-in for MySQL, and lets you pick from many storage engines and plugins.
PostgreSQL
A server database for apps where many people write at once. It's been ACID-compliant since 2001, and extensions such as PostGIS let it handle maps and location data as well.
When reports and analytics are the problem
This one keeps the in-process, no-server idea but changes what the engine is good at.
DuckDB
An analytical database that can run inside your process, on anything from edge devices to servers, reading and writing CSV, JSON, Parquet and Iceberg files.
When you're in the Java world
H2 Database Engine
A pure Java SQL engine shipped as a small jar, with embedded, server and in-memory modes, a JDBC API and fulltext search.
Want AI doing the heavy lifting in your marketing?
I build the systems that handle the boring 80 percent, so you get your week back. Done properly, with the human kept in.
When you'll ship the database inside a product
Firebird
A relational database with many ANSI SQL standard features, running on Linux, Windows and various Unix platforms. It says there are no fees for download, registration, licensing or deployment, even when you distribute it inside a commercial software package.
When the problem is distribution, or SQL itself
The last two are odd ones out, and that's the point: each solves a problem a relational swap won't.
RocksDB
A persistent key-value store you embed for fast storage, written in C++ around a log structured engine. It has no SQL, so only consider it if you never need queries.
Turso
Built on SQLite and aimed at one database per user, agent or tenant, with a cloud product that encrypts each database separately.
All seven side by side
| Database | Runs as | SQL? |
|---|---|---|
| DuckDB | In-process | Yes, analytical |
| Firebird | Relational engine | Yes |
| H2 Database Engine | Embedded or server | Yes, via JDBC |
| MariaDB | Server | Yes |
| PostgreSQL | Server | Yes |
| RocksDB | Library | No |
| Turso | Cloud service | Yes |
Only one row says no SQL, and only one says cloud service. Those are the two moves that change how your app is built, rather than which engine answers its queries, so give them the longest trial.
Two moves come up so often they have their own pages: going from SQLite to PostgreSQL for shared apps, and how DuckDB differs for analytics for reporting work.
Matching the move to your app
- A web app with many signed-in users writing at once: look at PostgreSQL or MariaDB first.
- A data notebook or reporting script over CSV or Parquet files: DuckDB was made for this.
- A Java desktop or server app that wants an embedded store: H2 runs in the same process through JDBC.
- A packaged product you'll install at customer sites: Firebird's deployment terms are written with that in mind.
- A SaaS product where each customer needs isolated data: Turso gives each tenant its own database.
- An app that only stores values by key: RocksDB skips SQL entirely.
What changes in your code
- Connection handling: a server database needs a host, credentials and a pool, where the file needed a path.
- Types and defaults: column types and date handling can behave differently, so test edge cases.
- Tests: the in-memory or temporary-file trick many test suites rely on may need replacing.
- Backups: copying one file becomes a dump, a snapshot or a managed backup.
- Deployment: something now has to start, monitor and upgrade the database alongside your app.
Checks before you migrate a single table
- Name the limit you've hit in one sentence: writers, network access, analytics, or per-user isolation.
- Match it to one group above and ignore the rest.
- Copy a realistic slice of production data into the candidate, not a toy sample.
- Rerun your five slowest queries and your busiest write path, and compare the results row for row.
- List every place your code assumes a single file: backups, tests, deployment scripts.
- Keep the old database readable until the new one has run cleanly through a full business cycle.
Frequently asked questions
Is DuckDB a replacement for an app's main database?
It's built for analytics, so it suits reports and local files; keep your app's main store where it is.
Is DuckDB free to use?
It's MIT-licensed, and the project is governed by the independent DuckDB Foundation.
Can H2 encrypt a database?
Yes. Encrypted databases are among its listed features.
Can Turso run inside my own cloud account?
Its cloud product offers a bring-your-own-cloud deployment, alongside per-database encryption.
Does PostgreSQL run on Windows and macOS?
Its own site says it runs on all major operating systems, so a local test copy is easy to set up.
Why would anyone pick a key-value store over SQL?
If your app only reads and writes values by key, it skips a query layer you'd never use.


