Quick answer
- In 1bench
- Right-click the table in the sidebar, choose Export Table, pick CSV, JSON, NDJSON or SQL, and save the file.
- In SQL
- sql
sqlite3 -header -csv shop.db "SELECT * FROM users;" > users.csvSwap -csv for -json to get a JSON array. For the whole database as SQL, run sqlite3 shop.db .dump > shop.sql.
Export visually in 1bench
1bench exports a SQLite table or view to CSV, JSON, NDJSON or SQL from the right-click menu, without the sqlite3 shell installed. You can export the whole table or only the rows you have filtered.
Prerequisite: download 1bench. Free 7-day trial, no sign-up.
- 1
Open your SQLite file
Connect to your .db, .sqlite or .sqlite3 file in 1bench and expand it in the sidebar to see its tables and views.
- 2
Choose Export Table
Right-click the table and choose Export Table. If the table is already open, the Export button in the bar at the bottom of the window does the same.
- 3
Narrow it down (optional)
To export only some rows, open the table, run a filter in its Query panel or sort by clicking a column header, then use the Export button at the bottom. The dialog offers Current view, with only those rows and the visible columns, or Whole table.
- 4
Pick a format
Choose SQL, NDJSON, CSV or JSON; SQL is selected first. For SQL, tick Include structure (CREATE TABLE statements) for the table and its indexes, Include data for the INSERT statements, or both.
- 5
Export and save
Click Export and choose where to save the file. A progress bar counts the rows written, Cancel stops a long export, and a message such as Exported 25 rows confirms it.
- There is no Export Database for SQLite, and the SQL export leaves out triggers. Use .dump or .backup below for a complete copy of the file.
- CSV always has a header row, writes NULL as an empty field and an empty string as "", and puts an apostrophe in front of text that starts with = + or @ so Excel does not run it as a formula.
- BLOB columns are written as hex starting with \x in CSV and JSON, and as X'...' literals in SQL. A view exports its CREATE VIEW statement in SQL mode, but no INSERT statements.
- A connection to a remote file in Live mode cannot export. Switch the connection to Snapshot mode, which works on a local copy, and reconnect.
Export with the sqlite3 shell and SQL
The sqlite3 command-line shell does the exporting. picks the output format, adds the column names, and or sends the results to a file instead of the screen. From your own shell, flags do the same in one line.
sqlite3 -header -csv shop.db "SELECT * FROM users;" > users.csv
Every command below gives the same result on SQLite 3.43, 3.50 and 3.54 unless a section says otherwise. Relative file names are resolved from the folder you started sqlite3 in.
Export to CSV
Inside the shell, set the mode and headers, then point the output at a file. keeps writing to the file until you run on its own; captures only the next query and then goes back to the screen.
| Command | What it does |
|---|---|
| Write the column names as the first row (off by default in scripts) | |
| Comma-separated, values with commas, quotes or spaces in double quotes | |
| Tab-separated | |
| Text written for NULL (default empty) | |
| Send all further output to a file | |
| Send output back to the screen | |
| Send only the next result to a file |
Example: export three columns of the users table to a CSV with a header.
.headers on
.mode csv
.output users.csv
SELECT id, name, email FROM users;
.output
The file starts with , then rows such as . If the folder does not exist, sqlite3 stops with .
Export a query to CSV
Any SELECT can go to a file, so filtering, joining and grouping happen before the export. is the easiest way to save one result without changing where later output goes.
Example: count audit events per action and save the summary.
.headers on
.mode csv
.once action_counts.csv
SELECT action, count(*) AS events, max(created_at) AS last_seen
FROM audit_log
GROUP BY action
ORDER BY events DESC;
The header row uses the names from the SELECT list, which is why gets an alias here.
Export all tables to CSV
The shell has no command for every table at once, but lists them, so a short loop in your own shell writes one CSV per table. The filter skips SQLite's internal tables such as .
for t in $(sqlite3 shop.db "SELECT name FROM sqlite_schema WHERE type = 'table' AND name NOT LIKE 'sqlite_%'"); do
sqlite3 -header -csv shop.db "SELECT * FROM \"$t\";" > "$t.csv"
done
On the demo database this writes app_settings.csv, audit_log.csv, feature_rollout.csv, migrations.csv and users.csv, each with a header row.
Export to JSON
writes each result as one JSON array of objects, and the flag does the same from your own shell.
sqlite3 -json shop.db "SELECT key, value FROM app_settings WHERE key LIKE 'app.%'" > app_settings.json
Two things catch people out. A query that returns no rows writes nothing at all, not , and two SELECT statements in a row write two separate arrays, which is not valid JSON as a single file. Building the JSON in SQL with and avoids both, because it always returns exactly one value.
Example: export audit events whose details column already holds JSON text.
SELECT json_group_array(
json_object('id', id, 'action', action, 'details', json(details))
)
FROM (SELECT * FROM audit_log WHERE details IS NOT NULL ORDER BY id LIMIT 2);
Run it with and to save the result. The call matters: without it, and both write the details as an escaped string () instead of a nested object.
Export to Excel
SQLite cannot write .xlsx files, so the usual route is CSV. Add to or so Excel reads the file as UTF-8 instead of guessing the encoding, which garbles accented names.
.headers on
.mode csv
.once --bom users_excel.csv
SELECT id, name, email FROM users;
goes one step further: it writes the next result to a temporary CSV and opens it in your default spreadsheet app. It also takes . Run first so the sheet gets column names.
.headers on
.excel
SELECT id, name, email FROM users;
For a real .xlsx file with one sheet per table, use pandas (see the Python section).
Dump to SQL with .dump
writes the database as SQL text: , then every CREATE statement and one INSERT per row inside a single transaction. Load it with input redirection to rebuild the database.
sqlite3 shop.db .dump > shop.sql
sqlite3 restored.db < shop.sql
dumps one table, and the argument is a LIKE pattern, so matches every table that starts with audit. The pattern is matched against object names, so leaves out the table's indexes and triggers. Name them too when you need them:
.output audit_log.sql
.dump audit_log idx_audit_log%
.output
Loading a dump into a database that already has the table fails with . Start from a new file, or drop the table first.
SQLite 3.54 writes REAL values in a dump without the trailing .0 ( rather than in 3.50). The column's REAL type converts them back on load, so the restored data is the same.
Schema only and data only
prints every CREATE statement without data, and prints one table. Add when you plan to load the file, because the plain output includes , which fails on load with .
.output schema.sql
.schema --nosys
.output
writes only the INSERT statements, ready to load into a database that already has the schema.
sqlite3 shop.db ".dump --data-only" > data.sql
sqlite3 new.db < schema.sql
sqlite3 new.db < data.sql
The data file also restores the AUTOINCREMENT counters in , and the versions differ here. A 3.50 file appends the counter rows, so the new database ends up with each one twice. That is untidy but harmless: the next insert still got id 26 after 25 rows. A 3.54 file clears them first, but loading it prints and exits with status 1, even though every row and counter loads.
Copy the database with .backup or VACUUM INTO
For a full copy you can open straight away, copy the file itself rather than its SQL. uses SQLite's online backup API, so it is safe while other connections are writing, and it overwrites the target if it exists. is plain SQL, so it works from any client, and it writes a compacted copy without free pages.
.backup shop-backup.db
VACUUM INTO 'shop-copy.db';
refuses to overwrite: if the file exists it stops with . Both also work on an in-memory database, which is the simplest way to save one to disk.
From Python
Python's built-in sqlite3 module covers CSV, JSON, dumps and backups without extra packages. The CSV header comes from .
import csv
import json
import sqlite3
con = sqlite3.connect("shop.db")
cur = con.execute("SELECT id, name, email FROM users ORDER BY id")
with open("users.csv", "w", newline="", encoding="utf-8") as f:
writer = csv.writer(f)
writer.writerow([col[0] for col in cur.description])
writer.writerows(cur)
con.row_factory = sqlite3.Row
rows = [dict(r) for r in con.execute("SELECT * FROM app_settings")]
with open("app_settings.json", "w", encoding="utf-8") as f:
json.dump(rows, f, indent=2)
with open("shop.sql", "w", encoding="utf-8") as f:
for line in con.iterdump():
f.write(line + "\n")
backup = sqlite3.connect("shop-backup.db")
con.backup(backup)
backup.close()
gives the same kind of SQL as , and is the same API as the shell's .
Example: write three tables to one Excel workbook, one sheet each. This needs .
import sqlite3
import pandas as pd
con = sqlite3.connect("shop.db")
with pd.ExcelWriter("shop.xlsx") as writer:
for table in ["users", "audit_log", "app_settings"]:
df = pd.read_sql_query(f'SELECT * FROM "{table}"', con)
df.to_excel(writer, sheet_name=table, index=False)
con.close()