tutorials/sqlite/export-data

SQLite Export to CSV, JSON, Excel and SQL Dumps

There are two ways to get data out of SQLite. Export a table visually in 1bench with a few clicks, or use the sqlite3 shell, where .mode and .output send any query to a CSV or JSON file and .dump writes the whole database as SQL.

Updated Nov 2, 2026Tested against SQLite 3.50.4 and 3.54.1, plus the macOS system sqlite3 3.43.2

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.csv

Swap -csv for -json to get a JSON array. For the whole database as SQL, run sqlite3 shop.db .dump > shop.sql.

1bench
No SQL needed

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. 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. 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. 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. 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. 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.

Good to know
  • 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.
The manual way

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.

bash
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.

CommandWhat 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.

text
.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.

text
.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 .

bash
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.

bash
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.

sql
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.

text
.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.

text
.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.

bash
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:

text
.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 .

text
.output schema.sql
.schema --nosys
.output

writes only the INSERT statements, ready to load into a database that already has the schema.

bash
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.

text
.backup shop-backup.db
sql
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 .

python
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 .

python
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()

Work with SQLite in one window

1bench is a desktop GUI for SQLite. Browse tables, filter rows, run SQL and export what you see, with the SQL still there when you want it.

Open SQLite in 1bench

Frequently asked questions

Why does my SQLite CSV export have no column names?
The sqlite3 shell starts with headers off when it reads from a script or runs a command from your own shell, and .mode csv does not turn them on. Run .headers on before the query, or pass -header on the command line. The column names come from the SELECT list, so use AS to rename one, for example SELECT count(*) AS events.
What is the difference between .dump and .backup in SQLite?
.dump writes SQL text: CREATE statements and one INSERT per row, which you can read, diff and load into another SQLite version with sqlite3 new.db < shop.sql. .backup copies the database pages into a new .db file, which is faster and keeps everything byte for byte, including settings such as the page size. Use .dump to move or inspect data, .backup or VACUUM INTO for a copy you can open straight away.
How do I save an in-memory SQLite database to disk?
Run .backup notes.db in the sqlite3 shell, or VACUUM INTO 'notes.db' from any SQL client, while the in-memory database is still open. Both write a normal database file you can open later. In Python, open a file connection and call mem.backup(disk) on the :memory: connection.
How do I export a BLOB from SQLite to a file?
The sqlite3 shell has a writefile() function that writes a value to disk and returns the number of bytes, for example SELECT writefile('logo.png', data) FROM images WHERE id = 1. Build the file name from a column to write one file per row. writefile() exists only in the shell, so in Python read the BLOB and write the bytes with open(path, 'wb').