SQLite File Viewer
Inspect SQLite tables, schema, values, and one read-only query locally, with a receipt for WAL state and each safety boundary.
- SECURE
- NO UPLOADS
- NO SIGNUP
- BROWSER BASED
- FREE
- FOREVER.
Support us with a link or a share
Drop one SQLite database here
The first 100 bytes are checked locally before the database engine loads. No upload, no account.
Runs in your browser. The source file, schema, queries, values, and CSV are not uploaded or saved in browser storage.
What this SQLite file viewer opens
A file named app.db, history.sqlite, or
catalog.sqlite3 often contains a complete relational database in one binary
document. The useful first question is rarely how to edit it. It is what tables exist,
what those tables declare, which values are actually present, and whether the file can be
inspected without installing a desktop database application. The viewer above is designed
for that narrower read-only job.
The ending is only a hint. .db is not a file format and many unrelated
applications use it. A real SQLite database begins with a defined header and has an
internal page structure that the SQLite engine can open. This page checks both instead of
trusting a familiar-looking filename. A file with the wrong header receives one careful
answer: it may be encrypted, damaged, or not SQLite at all. The first bytes cannot
distinguish those cases, so the page does not pretend that they can.
The header receipt comes before the database engine
The first inspection reads the 100-byte SQLite header locally. Before the heavier engine starts, the receipt names the file size, page size, read and write journal versions, page count, schema cookie and schema format, user version, application ID, text encoding, and freelist facts supported by that header. Those are source facts, not guesses produced from the filename and not values copied from a web service.
This order matters for both clarity and safety. You can see what the file claims before asking it a query, and an unsupported case can stop before the WebAssembly module is fetched. The engine is a versioned, self-hosted copy of official SQLite Wasm. It loads only after a selected file has passed the local header preflight; it is not part of the static page shell, and no database bytes are attached to that code request.
Why a WAL-marked main file is refused
SQLite can commit changes into a write-ahead log before those changes are copied back into
the main database. In that mode the state is a group: the main file, its -wal
sidecar, and normally its -shm sidecar. Opening the main file alone may show an
older schema or older rows while looking perfectly successful. A polished table full of
stale data would be a worse result than an explicit refusal.
This first version accepts one file and deliberately does not implement a sidecar-aware virtual file system. When header byte 18 or 19 marks WAL mode, the page stops and explains that the required sidecar set is unsupported. It does so even when a particular main file might happen to be fully checkpointed. That conservative boundary is visible in the receipt and can be reviewed; there is no hidden attempt to ignore a journal file and carry on.
Read-only is checked twice, not inferred from a button label
The browser cannot rewrite the original File selected from your computer, but
that fact alone does not make a database session read-only. The viewer copies the bytes into
a dedicated worker, opens that in-memory copy with SQLite’s read-only flag, and asks
sqlite3_db_readonly() to confirm the resulting database handle. The confirmation
belongs on the result receipt because “read-only” is a property to verify, not a mood set
by a disabled Save button.
A second check applies to every query. The page accepts exactly one
SELECT statement or one WITH … SELECT statement.
It rejects multiple statements, ATTACH, mutations, and user-entered
PRAGMA. That visible policy is useful, but it is not the final guard. SQLite
prepares the submitted statement and sqlite3_stmt_readonly() must confirm it
cannot write before execution begins. Merely checking whether the text starts with the word
SELECT would miss comments, compound input, and writable statements hidden behind a
plausible prefix.
Tables, views, declared schema, and typed cells
After the database opens, the first inventory separates tables from views and shows their declared SQL. Selecting one gives a bounded page of rows rather than drawing an entire million-row table into the document. Page controls and returned-row counts make the bound visible. The same result area is used for a custom read-only query, so there is not a second query playground hiding behind a different interpretation of the file.
SQLite values retain their types in the preview. NULL is labeled as NULL rather
than rendered as an empty cell. Empty text remains empty text. Integers and real numbers are
not silently relabeled as strings, and a BLOB is identified as bytes with a bounded
representation rather than decoded as if arbitrary binary data were UTF-8. That distinction
is important when the point of opening the database is to understand why an application
treats two apparently blank fields differently.
If what you have is SQL source rather than a SQLite database, use the
SQL query formatter. A .sql file is text made
of statements; a .sqlite file is a binary B-tree database. Renaming one to the
other does not convert it. For a MySQL-style dump whose INSERT rows need to become a table,
SQL to CSV handles that separate text-file job.
The query budget and Cancel button are real boundaries
A read-only query can still consume unbounded time. A cross join, recursive common-table expression, or scan through a large unindexed table does not need write access to freeze a tab. Work therefore runs behind SQLite’s progress handler with a measured operation and time budget. The active budget and returned row bound are printed with the result rather than implied by an animated timer.
Cancel terminates the worker instead of merely hiding its progress panel. A replacement worker performs a new readiness handshake, and a generation number prevents the old task from dropping a late result into the next file or query. Choosing another file applies the same rule. Choosing another table or editing the query invalidates the previous export while keeping the verified read-only source available, so ordinary exploration does not require loading the file again.
CSV is an exit for this result, not a database conversion
The download contains the current query result only. It does not contain indexes, triggers, foreign keys, constraints, views, collations, or tables you did not select, and it cannot be used to reconstruct the original database. The CSV is UTF-8 with a byte order mark for spreadsheet compatibility, uses CRLF records and RFC-4180-style double-quote escaping, and writes the column names in its first row.
The representation boundaries are stated rather than hidden. SQL NULL becomes an unquoted
empty field, empty text becomes a quoted empty field, and BLOB bytes become uppercase
SQLite hex such as X'00FF'. Spreadsheet applications do not all preserve the
distinction between NULL and empty text on import, and an ordinary text value may resemble a
hexadecimal BLOB marker, so the receipt calls the CSV a lossy tabular projection. Text cells
beginning with a spreadsheet formula marker are prefixed with an apostrophe and counted in
the receipt. That changes those exported text cells intentionally to prevent a downloaded
data file from becoming executable spreadsheet input.
You can inspect that exported table with the CSV viewer before opening it in a spreadsheet. If the question is whether the source file itself stayed byte-for-byte the same, the SHA-256 checksum tool gives the original an independent digest before and after inspection; the SQLite viewer never offers a write-back path.
Large databases are advised about, never rejected by a fixed ceiling
A browser tab has finite memory, and an in-memory SQLite session temporarily holds more than one copy of the file while ownership moves from the page into the worker and then into the engine’s file system. The page gives the shared memory advice before that allocation starts. It does not turn the advice into a hard file-size limit: the action remains available, and the browser gets to report whether this device can provide the memory.
Results are bounded for a different reason. A database may fit in memory while its query returns millions of rows, and rendering all of those cells would make the interface unusable. The screen shows pages. Full CSV export returns bounded chunks from the dedicated worker while the page remains responsive, and reports completed rows. File size, preview rows, exported rows, and query time are separate limits and appear separately; none is disguised as a generic “large file” error.
What the viewer deliberately does not claim
This is not a generic DB-file opener. dBase, Access, Berkeley DB, application caches, and
proprietary files may all use .db, but they do not become SQLite because the
extension matches. It is not an editor, schema designer, repair utility, password prompt,
SQLCipher diagnosis, remote database client, or arbitrary SQL shell. It does not save a
changed copy. It does not accept a URL. It does not quietly enable arbitrary introspection
pragmas supplied by the user.
Those omissions make the receipt meaningful. A viewer that also edits needs transaction, persistence, rollback, and download verification. A recovery tool needs evidence that can distinguish damage from encryption. A remote client needs credentials and a network boundary. None of those contracts can be borrowed from a local read-only file viewer merely because the same engine understands SQL.
No upload, no persistent database, and a check you can perform
Header inspection, engine startup, schema queries, table previews, custom read-only queries, and CSV generation happen in this browser tab. The copied database lives in worker memory. It is not written to localStorage, IndexedDB, Cache Storage, or OPFS, and the page has no route for posting the source, query, values, filename, or result to a remote database or an upload service.
The engine and its Wasm binary are same-origin application assets and load after the first accepted file, so seeing those GET requests is expected. Seeing the database travel in a POST or PUT is not. The guide to verifying local processing shows how to make that distinction in the Network panel and how to check browser storage after a reset. The promise here is intentionally specific enough to test: code may arrive, but your selected database does not leave.
Questions
How do I open a SQLite file in this viewer?
Choose or drop one local .sqlite, .sqlite3, .db, or .db3 file. The extension only helps the file picker; the page checks the SQLite header before it loads the database engine. Once the copied database opens read-only, you can inspect tables, views, declared schema, typed values, and a bounded query result.
Is a .db file always a SQLite database?
No. .db is a generic extension used by unrelated products. This viewer accepts only a recognized SQLite format and then asks SQLite itself to open it. If the header is not recognized, the honest result is that the file may be encrypted, corrupt, or not SQLite; the header alone cannot prove which one.
Can the viewer change my database?
No. The selected File is copied into worker memory and opened with SQLite's read-only flag. The receipt also checks sqlite3_db_readonly() on the database handle, and every prepared user statement must pass sqlite3_stmt_readonly() before execution. There is no save-database or write-back path.
Why is a WAL database refused?
A database in write-ahead logging mode can have committed changes in its -wal sidecar that are not yet present in the main file. This version accepts one file, not the required main, -wal, and -shm set, so showing the main file could silently show stale data. It refuses that case instead.
Which SQL can I run?
Exactly one read-only SELECT or WITH ... SELECT statement. Multiple statements, ATTACH, mutation, and user-entered PRAGMA are outside this viewer. A text-prefix check is not the safety boundary: SQLite prepares the statement and confirms that it is read-only before execution.
Is CSV a lossless copy of the database?
No. CSV contains the current tabular result, not indexes, constraints, triggers, SQLite types, or the rest of the database. The receipt states how NULL and BLOB values are represented, which text cells were neutralized for spreadsheet formulas, how quoting works, and whether the on-screen preview was bounded.
Is the database uploaded or saved in browser storage?
No. The file is read in this tab and copied into an in-memory worker. The source, schema, query, values, and CSV are not posted, and the database is not placed in localStorage, IndexedDB, Cache Storage, or OPFS. The versioned SQLite engine loads from the same site only after you choose a recognized file.