Skip to content

Download production D1 data to local

When your app is live on Cloudflare, your D1 database lives at the edge. Here’s how to pull that data down to your local machine for debugging, backups, or offline development.

Terminal window
wrangler d1 execute <database-name> --remote --command "SELECT * FROM users" --output users.json

This runs a SQL query against your remote D1 database and writes the results to a JSON file. Replace <database-name> with your D1 database name from wrangler.toml.

The starter includes four tables: users, sessions, password_resets, and uploads. To export everything:

Terminal window
# Export each table to JSON
wrangler d1 execute <database-name> --remote --command "SELECT * FROM users" --output export/users.json
wrangler d1 execute <database-name> --remote --command "SELECT * FROM sessions" --output export/sessions.json
wrangler d1 execute <database-name> --remote --command "SELECT * FROM password_resets" --output export/password_resets.json
wrangler d1 execute <database-name> --remote --command "SELECT * FROM uploads" --output export/uploads.json

After exporting, push the data into your local D1 database:

Terminal window
# Apply migrations first (if local DB is empty)
wrangler d1 migrations apply <database-name> --local
# Import each table
wrangler d1 execute <database-name> --local --file export/users.json
wrangler d1 execute <database-name> --local --file export/sessions.json
wrangler d1 execute <database-name> --local --file export/password_resets.json
wrangler d1 execute <database-name> --local --file export/uploads.json

If you prefer a SQL dump (like pg_dump), use the --export flag:

Terminal window
wrangler d1 execute <database-name> --remote --export ./backup.sql

This produces a .sql file with INSERT statements for all tables. To restore locally:

Terminal window
wrangler d1 execute <database-name> --local --file ./backup.sql

Add a script to your package.json:

{
"scripts": {
"db:pull": "wrangler d1 execute <database-name> --remote --export ./backup.sql && wrangler d1 execute <database-name> --local --file ./backup.sql"
}
}

Then bun run db:pull syncs remote to local in one step.

D1 only stores database rows. If your app has file uploads (avatars, etc.), those live on disk or in R2 — not in D1. To download uploaded files from production, you’ll need to fetch them via HTTP or sync from your R2 bucket:

Terminal window
# If using R2 for uploads
wrangler r2 object get <bucket-name>/avatar-123.png ./local-uploads/avatar-123.png
  • --remote hits your production database — read queries are safe, but never run DELETE or UPDATE with --remote unless you mean it.
  • D1 export is not a full backup — it exports data, not schema. Schema lives in your migrations/ folder, which is version-controlled.
  • Large exports may time out — D1 has a 30-second query duration limit. For very large tables, export in chunks with LIMIT and OFFSET.