Somebody just handed you a .db file
It starts with an attachment. A bug report lands in your inbox with a file called sessions.db — 38 megabytes of somebody else's bad afternoon — and a note reading, the reproducing data is in here. The engineer who exported it has already left for two weeks of vacation. Your laptop has no SQLite client on it, and installing one means a ticket, an approval queue, and a wait.
You could write a Python script. You have before, and you will again, but that is twenty minutes of environment wrangling for a five-minute look at five rows. You could upload the file to an online converter, except this database holds user emails, session tokens, and at least one API key you recognize, so that option is really not an option.
This page is the fourth path. Drag the file into the SQLite Viewer and the entire engine — the actual SQLite library, compiled to WebAssembly — spins up inside your browser tab. You get the table list, the schema, a paginated row browser, a query box, and a CSV export button. Nothing installs, and nothing uploads. In the time it took you to read this paragraph, you could already be looking at the data.
A quick orientation to what you are holding: SQLite is not a server you connect to. It is a single, self-contained, cross-platform file, which is one reason the project describes it as the most widely deployed database engine in the world. Every iPhone stores messages in SQLite. Chrome keeps your browsing history in it. Flight recorders, smart thermostats, and half the apps in your pocket ship it. A .db extension on a mystery file is less a format problem than an invitation.
Opening and exploring a database, start to finish
The workflow below covers about 95 percent of what people need from a viewer. If you have the file handy, follow along — every step happens on this page, above the fold, with no account in sight.
Drop in the file
Drag any .db, .sqlite, or .sqlite3 file onto the viewer, or click the file picker. The browser hands the bytes to the tool through the standard FileReader interface, and the file is read straight into memory on your device — no upload step exists in the code.
Pick a table from the list
The sidebar fills with every table the file contains, along with views and triggers where present. Click one and the first page of rows appears, with column names taken from the table definition itself rather than guessed from the data.
Read the schema when columns surprise you
The schema view shows the raw CREATE TABLE statement for the selected table. When a column is named payload or extra and turns out to hold serialized JSON, the schema is where you find out — and where you learn the column is allowed to be null.
Query it like you would anywhere else
The SQL box accepts any SELECT statement: joins, GROUP BY, window functions, LIKE, date functions, the lot. The one firm rule is reads only, which we will defend in the edge-cases section because it has saved people real pain.
Export what you found
Run a query, then export the current result set as CSV. Narrow it with WHERE clauses first — the export matches exactly what the query returned, nothing more and nothing less.
Close the tab when you are done
There is no session, no file history, and no account to log out of. Closing the tab releases the in-memory copy of the database, and it is gone.
How the file becomes tables on your screen
A SQLite file is a sequence of fixed-size pages, and the first page starts with a 100-byte header. The first 16 bytes of that header are a magic string — SQLite format 3 followed by a zero byte — which is how any tool, including this one, distinguishes a real database from a renamed spreadsheet or a truncated download. Byte 16 and 17 of the header state the page size, always a power of two between 512 and 65,536. Every table and index is a b-tree spread across those pages, with interior pages pointing to leaf pages that hold the actual rows.
Before showing you anything, the viewer reads a special table called sqlite_master. It is the catalog: one row for every table, view, index, and trigger in the file, each with the root page number and the original SQL text that created it. That is how the sidebar table list is built — not by scanning for plausible-looking data, but by reading the same catalog the C library consults on every connection.
The engine doing the reading is sql.js: the official SQLite source compiled to WebAssembly with Emscripten. That distinction matters more than it sounds. Many browser tools re-implement enough of a format to fake it, and then feed you wrong numbers on the first unusual file. sql.js is not a reimplementation. Same parser, same planner, same executor — so the rows you see are the rows the sqlite3 command line would print, character for character.
There is a small caveat worth knowing when you compare tools: SQLite the library moves forward, and the compiled build in your tab corresponds to a specific release family. If a database was written by a much newer engine using freshly added syntax or pragmas, the viewer's build lags the native install you may have at work. It is rare, it is visible, and it is fixable on our side by rebuilding against the latest source.
If your work sits closer to the text-config side of data, we keep a sibling tool for the other format that shows up in bug reports: the YAML Validator pinpoints broken workflow files the same way this viewer pinpoints broken databases — locally, with the offending line highlighted.
Column types are more suggestion than law
SQLite has five storage classes and a system of type affinity that trips up everyone who arrives from stricter databases. Affinity is a preference, not a constraint: an INTEGER column would like whole numbers, and will coerce strings that look like whole numbers, but you can still insert the word banana and SQLite will store it without complaint.
| Declared type | Affinity | What tends to live there |
|---|---|---|
| TEXT | TEXT | Strings, plus anything that refuses numeric coercion |
| INTEGER | INTEGER | Whole numbers; booleans as 0 and 1; rowid aliases |
| REAL | REAL | Floating-point values, stored in eight bytes |
| NUMERIC | NUMERIC | Values that stay numeric when conversion is lossless |
| BLOB | BLOB | Raw bytes: images, protobuf blobs, serialized objects |
This looseness is why browsing beats assuming. A column declared INTEGER can hold text in row 4012 after a bad import, and nothing in the schema will warn you. The row browser shows every stored class, so the oddball row is visible the moment you page onto it — which is precisely the moment a report quietly goes wrong downstream.
One more concept that explains half the weird tables you will meet: rowid. Every ordinary table has a hidden 64-bit integer key, and a column declared INTEGER PRIMARY KEY becomes an alias for it. That is why so many schemas use id INTEGER PRIMARY KEY and why those ids never repeat even after deletes. Tables can opt out with WITHOUT ROWID, but in a decade of opening other people's files we have met it a handful of times.
A five-minute audit, shown end to end
Here is a real-shaped session. An online store hands support a database export to investigate refund complaints: orders.db, two tables, a few hundred rows. The questions are simple — how bad is it, and who is affected — and every answer fits in one query.
Input
CREATE TABLE customers ( id INTEGER PRIMARY KEY, name TEXT, email TEXT, country TEXT ); CREATE TABLE orders ( id INTEGER PRIMARY KEY, customer_id INTEGER REFERENCES customers(id), status TEXT, total REAL, placed_at TEXT );
Output
Table list: customers (214 rows), orders (533 rows). Views: none. Triggers: none. Elapsed time before first row visible: under two seconds on a normal laptop.
Input
SELECT status,
COUNT(*) AS n,
ROUND(AVG(total), 2) AS avg_total
FROM orders
GROUP BY status
ORDER BY n DESC;Output
shipped 412 rows avg 128.44 pending 87 rows avg 96.10 refunded 23 rows avg 101.77 cancelled 11 rows avg 88.05
Already interesting: the average refunded order is worth more than the average shipped one, so the complaints are not noise. The next question writes itself — which customers account for the refunds, and are they repeat refunders?
Input
SELECT c.name, c.country,
SUM(o.total) AS spend,
COUNT(*) AS order_count
FROM orders o
JOIN customers c ON c.id = o.customer_id
WHERE o.status = 'refunded'
GROUP BY c.id
ORDER BY spend DESC
LIMIT 3;Output
Mara Lindqvist SE 612.40 4 orders Devon Cole US 487.15 3 orders Priya Nair IN 431.90 3 orders
Four refunds from one account in a small export is a pattern worth an email. Export that result set as CSV, attach it to the ticket, and the investigation is documented. Total time from dropped file to attached evidence: about five minutes, none of it spent installing anything.
When the viewer pushes back, and what it means
A good tool fails loudly and explains itself. These are the four refusals you are most likely to meet, what each one actually means, and what to do about it.
| Symptom | Likely cause | What to try |
|---|---|---|
| Error: file is not a database | Encryption (SQLCipher or similar), corruption, or not SQLite at all | Ask the sender how the export was made and whether a passphrase exists; check the file really is a database |
| Tables look out of date | Recent commits are sitting in a .db-wal sidecar file | Copy the .db-wal and .db-shm files too and load them together, or request a checkpointed export |
| The tab slows or stalls | Database size exceeds comfortable browser memory | Use a native desktop client for multi-gigabyte files; keep this viewer for the hundreds-of-megabytes range |
| Rows show as [object] or gibberish | Blob columns holding binary or encrypted payloads | Read the CREATE TABLE statement in the schema view; export blobs separately if needed |
The write-ahead log deserves a fuller explanation because it catches careful people. SQLite in default journal mode appends committed changes to a sidecar file ending in .db-wal and merges them into the main file later, at a checkpoint. If someone copies the .db while the database is live — pulling it off a running phone, for instance — the copy can be missing everything since the last checkpoint. The fix is boring and effective: always take the sidecar files along with the database.
Encrypted databases fail with the same blunt error as garbage files, and that is by design. SQLCipher wraps the real file in AES encryption, and a tool that could open it without the passphrase would make the encryption pointless. If your organization uses encrypted SQLite, you need the matching native tool and the key — no browser viewer can or should substitute.
Memory limits are the honest ceiling. The WebAssembly engine holds the whole database in the tab, so a 300 MB export is comfortable and a 5 GB archive is asking for a crash rather than an error message. There is no paging from disk in the browser, so we say so plainly instead of letting you discover it.
The people who keep a viewer bookmarked
QA engineers were the first regulars. They reproduce a bug, export the application database from the device or emulator, and need to check state — did the dedupe fix actually remove the duplicate rows before the release build? A read-only viewer answers that in seconds, and read-only means a tired tester at 6 p.m. cannot damage the evidence.
Mobile developers arrive with specific files: msgstore.db from a WhatsApp backup, Chrome's History and Cookies databases, an analytics SDK's cache. Digital forensics students open the same artifacts for coursework, minus the expensive tooling their labs license. Data journalists show up too, because newsrooms increasingly publish source datasets as SQLite — it is compact, queryable, and reads the same on every operating system.
- Checking whether a fix changed what the app stored, before the next release build
- Reading a third-party SDK's cache to see exactly what it collected
- Opening a course database — Chinook, Northwind ports, Sakila exports — without installing anything
- Verifying the contents of a vendor export before feeding it into a pipeline
- Skimming a Chrome or WhatsApp artifact during a security review
The common thread is inspection under constraints: no install permitted, no time to spare, or data too sensitive to upload. If none of those constraints apply to you, a native client will serve you just as well — and we will say exactly that in the comparison below rather than pretend otherwise.
Four ways to open the same file
We like this viewer, and we also like honest comparisons. Here is where each approach earns its keep, including the situations where you should close this tab and reach for something heavier.
| Approach | Install needed | Writes allowed | File leaves your machine | Best for |
|---|---|---|---|---|
| This viewer | None | No — SELECT only | Never | Fast, private inspection and CSV export |
| DB Browser for SQLite | Desktop app | Yes, full editing | No | Long sessions, edits, imports, visual design work |
| sqlite3 command line | Often preinstalled on dev machines | Yes | No | Scripted checks, server-side and versioned work |
| Upload converters | None | Rarely | Yes — the entire file | Frankly, we cannot recommend one for anything private |
The write access row deserves a comment. The moment your task shifts from looking to changing — cleaning a dataset, patching a bad migration, designing a schema — get DB Browser for SQLite or use the command line. A browser viewer that also wrote would combine the power of a knife with the safety of none, and most files opened here are one-of-a-kind exports that cannot be regenerated.
The upload row deserves two. Once a database leaves your machine you cannot un-send it, and databases are the least anonymous files people routinely handle: names, tokens, keys, and logs travel together. The no-install, no-upload combination is this tool's entire reason to exist, so we treat it as a promise rather than a feature.
Zero requests carry your data
Here is the mechanics, so you do not have to take it on faith. When you drop a file in, the browser reads it through the FileReader API into an ArrayBuffer — the same mechanism an offline image editor uses. The WebAssembly engine parses and queries that buffer in place. At no point does the file, any chunk of it, or any query result enter a network request.
You can audit the claim yourself in about thirty seconds. Open your browser's developer tools, switch to the Network tab, clear it, and load a database. Watch the requests that fire: scripts and page assets, none of them growing to the size of your file. Then disconnect from the internet and keep browsing tables — the viewer does not notice, because it never needed the network after load.
Nothing is stored, either. There is no account, no file history, no most-recent list, and nothing in localStorage that reconstructs your data. Close the tab and the copy of the database in memory is released with it. For anyone whose security team asks pointed questions about tooling, that paragraph is the whole answer.
Questions we hear about the SQLite Viewer
Does my .db file get uploaded to a server?
No. The file is read by the browser itself and parsed by a WebAssembly build of SQLite running in the same tab. You can confirm this by watching the Network panel in your browser's developer tools while you load a file — no request grows to match your database size, and the viewer keeps working after you go offline.
Can I edit rows, run UPDATE, or DELETE data?
The query box is read-only by design: SELECT statements work, and anything that mutates data is refused. That restriction protects you. Accidental writes are the most common way people ruin a single exported copy of a production database, and a viewer that cannot write cannot ruin anything.
Which file extensions does the viewer accept?
.db, .sqlite, .sqlite3, and .db3 all describe the same on-disk format. The viewer checks the file's actual header rather than trusting the extension, so a mislabeled file still opens and a renamed text file still gets rejected.
Why does my file fail with 'file is not a database'?
Three usual suspects: the file is encrypted (SQLCipher and similar wrappers add a layer the raw engine cannot read), the file is genuinely corrupt, or it was never SQLite to begin with. Ask whoever produced it how it was exported, and whether a passphrase is involved.
My tables look out of date. Where did the newest rows go?
Probably into a write-ahead log. SQLite may keep recent commits in a sidecar file ending in .db-wal, which gets folded into the main file later. Copy the .db-wal and .db-shm files along with the database and load them together, or ask the sender to checkpoint and re-export.
How large a database can it handle?
The WebAssembly engine holds the database in browser memory, so the practical ceiling is your available RAM. A few hundred megabytes is comfortable on a desktop machine; multi-gigabyte archives will strain the tab. For very large files, a native client is the better tool.
Is this the same engine as the SQLite I have installed?
It is the real SQLite source compiled to WebAssembly, so parsing, the query planner, and results match a native build of the same release family. What you lose are the surrounding utilities — backup APIs, shell dot-commands, and the ability to write.
Can I export a full table to CSV?
Yes. Select the table, or run SELECT * FROM your_table with any WHERE filter you want, and export the current result set as CSV. Filtering before export keeps the file small and the relevant rows obvious when you open it in a spreadsheet.
Where to head next
Databases rarely travel alone. If the rows you just exported feed into a JSON API, the JSON Viewer Online gives blob columns the same collapsible-tree treatment this page gives tables, and the JSON Editor Online is where those payloads go when they need fixing rather than reading.
Going the other direction: the SQL on CSV tool runs SELECT queries against plain CSV files with no database at all — handy when the vendor sends you a report instead of an export, or when you want to prototype the exact query you will run here before touching the real file. Both, like this viewer, do their work entirely in your browser.
Sources and further reading
- SQLite — Database File Format(sqlite.org)
- SQLite — Datatypes and Type Affinity(sqlite.org)
- SQLite — The Most Widely Deployed Database Engine(sqlite.org)
- sql.js — SQLite Compiled to WebAssembly(sql.js.org)
- sql.js Source Repository(github.com)
We cite primary sources (standards bodies, government agencies, official documentation) wherever they exist so you can verify every number on this page yourself.