Both are in-process, zero-config, single-file databases — the difference is the workload. SQLite is a row store tuned for transactional, point-read/write OLTP: app state, mobile, edge, embedded. DuckDB is a columnar, vectorized engine tuned for analytical OLAP: scans, aggregations, joins over large tables, and querying Parquet/CSV in place. They are complements, not rivals: SQLite stores your app’s rows; DuckDB crunches your analytics.
SQLite
The world’s most deployed embedded row-store database.
Same "just a library, just a file" ergonomics, opposite storage models. SQLite reads and writes individual rows fast and is everywhere. DuckDB stores columns and vectorizes execution, so it flies through aggregations and can query data lakes (Parquet) directly. Pick by whether your queries touch a few rows or scan millions.
Quick takes
If you're…
You need app/local state with frequent small writes→SQLiteA row store handles point reads/writes and transactions well.
You run heavy aggregations over large tables→DuckDBColumnar + vectorized execution dominates analytical scans.
You want to query Parquet/CSV files in place→DuckDBDuckDB reads Parquet/CSV directly without loading them in.
You are on mobile, edge, or embedding in an app→SQLiteSQLite is the ubiquitous, rock-solid embedded OLTP choice.
You want a local analytics engine in a notebook→DuckDBDuckDB pairs perfectly with pandas/Polars and notebooks.