SQLite Database
A SQLite file is a self-contained relational database in a single binary file — behind every WhatsApp chat, every Chrome history, and over a trillion active deployments worldwide. Created for the US Navy in 2000, it is the most-deployed database engine in history.
SQLite conversion is not yet available in FileDex. For now, use the CLI commands in the Developer Door to export or convert between database formats with sqlite3 or DB Browser for SQLite.
Common questions
How many databases use SQLite worldwide?
SQLite estimates over 1 trillion active deployments. It ships in every Android and iOS device, every major web browser (Chrome, Firefox, Safari), macOS, Windows 10/11, and most TV set-top boxes and IoT devices. It is the most widely deployed database engine by a large margin.
Can multiple processes write to a SQLite database simultaneously?
SQLite supports unlimited concurrent readers but serializes writes with a database-level lock. WAL (Write-Ahead Logging) mode allows readers to proceed during writes, but only one writer can hold the lock at a time. For high-concurrency write workloads, use a client-server database like PostgreSQL.
How do I recover a corrupted SQLite database?
Run PRAGMA integrity_check to identify the corruption scope. Try sqlite3 corrupt.db '.dump' | sqlite3 recovered.db to export readable data to a new file. For deeper recovery, use the .recover command (SQLite 3.29.0+) which bypasses the B-tree and scans raw pages for extractable records.
What is the maximum size of a SQLite database?
The theoretical maximum is 281 terabytes (2^47 bytes with the default page size of 4096). In practice, SQLite databases work well up to tens of gigabytes. Performance degrades with very large databases primarily due to filesystem limitations and lack of concurrent write support.
How do I recover deleted data from a SQLite file?
SQLite marks deleted rows as freelist pages rather than physically erasing them. Until a VACUUM or database overwrite, the deleted data persists on disk. Use SQLite 3.29.0's `.recover` command, the undark recovery tool, or SQLite Forensic Explorer to extract deleted records from the freelist. Mobile forensic suites like Cellebrite and MSAB XRY build on these recovery primitives for investigations.
What makes .SQLITE special
Pick up your phone and you're holding dozens of SQLite databases: messages, contacts, browser history, every app's local cache. The extension might be .sqlite, .db, .sqlite3, .db3, or nothing at all — the engine doesn't care. The extension is the signal.
Continue reading — full technical deep dive
The File Extension Is Anything You Want. What Does That Tell You About the Format?
Open a file manager and look for databases. .sqlite is explicit — Thunderbird's places.sqlite announces its contents. .db is generic — every SQLite-based app can use it, and so can any other database engine. .sqlite3 declares the format version. .db3 does the same. Chrome's browser history lives in a file called History — no extension at all.
All of these contain the same 16 bytes at offset 0: 53 51 4C 69 74 65 20 66 6F 72 6D 61 74 20 33 00 — the ASCII string SQLite format 3 followed by a null byte. SQLite itself doesn't care what you name the file. The operating system doesn't care either. Only people do.
That matters for forensic triage. An investigator scanning a mobile device's /data/data/ directory can identify .sqlite-extensioned files instantly, while a generic .db requires content sniffing to distinguish SQLite from Berkeley DB, LevelDB, or something else entirely. Apps that want their storage to be inspectable choose .sqlite. Apps that want to stay opaque choose .db or nothing. The extension is a declaration about author intent, not a requirement of the format. Investigators know this. They skip the extension entirely and read the bytes.
Forensic Investigators Read the First 100 Bytes Before Anything Else. Why Those 100?
Every SQLite investigation begins with 100 bytes. The first 16 are the magic string. Offsets 16-20 reveal the rest.
Offset 0x10 holds the page size — a two-byte big-endian integer that must be a power of 2 between 512 and 65536 (the default is 4096). Offset 0x12 holds the write format version: 1 means rollback journal, 2 means Write-Ahead Logging (WAL). Offset 0x13 holds the matching read format version. Together these three bytes tell you the database's fundamental mode — and whether you need to look for a companion -wal file on disk.
The file change counter at offset 0x18 increments on every write transaction, so caching clients can detect whether the database changed since they last read it. The schema cookie at 0x28 increments when any CREATE/DROP/ALTER runs, telling prepared-statement caches to recompile. The text encoding at 0x38 (1 = UTF-8, 2 = UTF-16 little-endian, 3 = UTF-16 big-endian) determines how cell content is interpreted.
Finally, offset 0x60 holds the SQLite library version that most recently wrote the database — four bytes in decimal-packed format. 00 38 12 00 reads as 3.39.0. Forensic analysts fingerprint a database — last writer version, page size, journal mode — without opening it. 100 bytes tell the story, and version mismatches can reveal tampering or version-specific bugs. Headers reveal what is in the file. The sidecar files next to it reveal what is not yet committed.
Copy a SQLite File Without the -wal Sidecar. You Just Lost Committed Transactions. Why?
Open a SQLite database in WAL mode and a second file appears next to it. database.db is the main file. database.db-wal is the Write-Ahead Log. database.db-shm is a shared memory index used when multiple processes access the database concurrently. Delete the -wal file while it contains uncommitted pages and you've permanently lost those changes.
WAL replaced the traditional rollback journal (-journal) in SQLite 3.7.0 (July 2010). Instead of writing old-page copies before overwriting, WAL appends new-page copies to a separate file and merges them back into the main database at checkpoint time. The benefit is concurrency: readers can continue reading the main database while a writer appends to the WAL. The traditional rollback journal serialized all access.
For mobile forensics this is the common pitfall. WhatsApp's msgstore.db accumulates messages in msgstore.db-wal between checkpoints. An investigator who copies only the main file with cp misses the most recent messages entirely — sometimes days of conversation. The safe copy pattern is sqlite3 source.db '.backup destination.db', which reads through SQLite and includes pending WAL data.
Enable WAL mode with PRAGMA journal_mode=WAL;. Control checkpoint frequency with PRAGMA wal_autocheckpoint=1000;. Close all connections to force a checkpoint — or run PRAGMA wal_checkpoint(TRUNCATE); explicitly. WAL behavior is an engineering detail. The scale at which it runs is the astonishing part.
One Trillion Active SQLite Deployments. How Did It Get There?
Your phone contains dozens of SQLite databases right now. Messages, contacts, browser history, every app's local cache, every system configuration store. WhatsApp's msgstore.db.crypt14 holds years of chat. Apple Messages keeps everything in chat.db. Signal, Telegram, Slack, Discord — all use SQLite. Chrome's History file. Firefox's places.sqlite. Safari's History.db. Every major consumer app on the planet uses SQLite for local caching and offline functionality.
Android ships SQLite as a core framework component. iOS uses Core Data built on SQLite. macOS's Mail and Safari both use it internally. Every Windows 10/11 installation contains SQLite databases for system features. The sqlite.org project estimates over one trillion active deployments worldwide — more than every other database engine combined by orders of magnitude.
Mobile forensic workflows start with SQLite. Extract the app's /data/data/<package>/databases/ directory. Open each file with sqlite3 or DB Browser for SQLite. Recover deleted rows from freelist pages using SQLite 3.29.0's .recover command. The scale is remarkable: most people carry 50-100 SQLite databases in their pocket every day, and every mobile investigation depends on reading them.
.SQLITE compared to alternatives
| Formats | Criteria | Winner |
|---|---|---|
| .SQLITE vs .MYSQL | Deployment model SQLite is a single file with zero configuration. MySQL requires a running server process, user accounts, network configuration, and ongoing administration. | SQLITE wins |
| .SQLITE vs .MYSQL | Concurrent writes MySQL handles thousands of concurrent write connections using row-level locking. SQLite serializes all writes through a single database-level lock. | MYSQL wins |
| .SQLITE vs .POSTGRESQL | SQL feature completeness PostgreSQL supports FULL OUTER JOIN, advanced ALTER TABLE, stored procedures (PL/pgSQL), custom types, and extensions (PostGIS, pg_trgm). SQLite lacks many of these features. | POSTGRESQL wins |
| .SQLITE vs .JSON FILE | Query capability SQLite supports SQL queries with JOINs, aggregation, window functions, and indexes for efficient lookups. JSON files require loading into memory and iterating through all records for every query. | SQLITE wins |
Technical reference
- MIME Type
application/vnd.sqlite3- Magic Bytes
53 51 4C 69 74 65 20 66 6F 72 6D 61 74 20 33 00SQLite format 3\0 text signature.- Developer
- D. Richard Hipp
- Year Introduced
- 2000
- Open Standard
- Yes — View specification
SQLite format 3\0 text signature.
Binary Structure
A SQLite database file begins with a 100-byte header containing the magic string 'SQLite format 3\000' (16 bytes), followed by configuration fields defining page size, file format versions, page counts, and encoding. The remainder of the file is divided into fixed-size pages. Page 1 starts at byte 0 and contains the header plus the root B-tree page for the sqlite_master table (the schema table). Subsequent pages are B-tree pages (table or index interior/leaf), overflow pages (for records exceeding one page), free pages (available for reuse), or pointer-map pages (in auto-vacuum mode). Table B-trees store records as variable-length cells containing the rowid and serialized column values. Index B-trees store index key values with pointers to the corresponding table rows. Each B-tree page has a page header (8 or 12 bytes) describing the page type, cell count, free space offset, and rightmost child pointer (interior pages only). The file change counter at offset 24 increments on every write transaction, enabling cache invalidation. In WAL (Write-Ahead Logging) mode, changes are written to a separate -wal file before being checkpointed back to the main database. A -journal file is used in rollback journal mode for atomic commits and crash recovery.
| Offset | Length | Field | Example | Description |
|---|---|---|---|---|
0x00 | 16 bytes | Magic string | 53 51 4C 69 74 65 20 66 6F 72 6D 61 74 20 33 00 | Header string 'SQLite format 3\0' — identifies the file as a SQLite database |
0x10 | 2 bytes | Page size | 10 00 (4096) | Database page size in bytes. Must be a power of 2 between 512 and 65536. Value 1 means 65536. |
0x12 | 1 byte | Write format version | 01 | File format write version. 1 = rollback journal, 2 = WAL mode. |
0x13 | 1 byte | Read format version | 01 | File format read version. 1 = rollback journal, 2 = WAL mode. |
0x14 | 1 byte | Reserved space | 00 | Bytes of unused space at end of each page. Usually 0. |
0x18 | 4 bytes | File change counter | 00 00 00 2A | Incremented on every write transaction. Used for cache validation. |
0x1C | 4 bytes | Database size (pages) | 00 00 00 08 | Total number of pages in the database file. |
0x20 | 4 bytes | First freelist trunk page | 00 00 00 00 | Page number of the first freelist trunk page. 0 if no free pages. |
0x24 | 4 bytes | Total freelist pages | 00 00 00 00 | Total number of freelist pages (available for reuse). |
0x28 | 4 bytes | Schema cookie | 00 00 00 05 | Incremented when the database schema changes. Triggers prepared statement recompilation. |
0x2C | 4 bytes | Schema format number | 00 00 00 04 | Schema format version. Current version is 4. |
0x34 | 4 bytes | Suggested cache size | 00 00 00 00 | Default page cache size suggested by PRAGMA default_cache_size. |
0x38 | 4 bytes | Text encoding | 00 00 00 01 | Text encoding. 1 = UTF-8, 2 = UTF-16le, 3 = UTF-16be. |
0x3C | 4 bytes | User version | 00 00 00 00 | User-defined version number. Set via PRAGMA user_version. Used by applications for schema versioning. |
0x60 | 4 bytes | SQLite version number | 00 38 12 00 (3.39.0) | SQLite library version that most recently wrote the database, in decimal encoding. |
SQLite conversion is not yet available in FileDex. For now, use the CLI commands in the Developer Door to export or convert between database formats with sqlite3 or DB Browser for SQLite.
Attack Vectors
- SQL injection via application code
- Malicious database files (CVE-2019-8457 magellan)
- Mobile data extraction
- ATTACH DATABASE filesystem access
Mitigation: Open SQLite files only from trusted sources. Inspect binary headers before full parsing when analyzing untrusted databases. Use `PRAGMA integrity_check` to detect corruption and schema tampering. Never load application SQLite files over a network without transport encryption. FileDex does not parse SQLite — this page is static, no upload.
- Specification SQLite File Format — sqlite.org/fileformat2.html
- Specification SQLite Command Line Interface (.backup, .recover, .dump)
- Documentation SQLite Write-Ahead Logging (WAL)
- Registry LOC FDD fdd000461 — SQLite Database File Format
- Registry PRONOM fmt/729 — SQLite Database File Format