Featured image of post DuckDB in Action: Database Backup & Migration — Snapshots, Exports, and Compressed Archives

DuckDB in Action: Database Backup & Migration — Snapshots, Exports, and Compressed Archives

A comprehensive guide to DuckDB's snapshot mechanism, EXPORT DATABASE, and compressed archiving with real-world production scenarios.

Introduction

When running DuckDB in production, data safety is paramount. Unlike traditional client-server databases like PostgreSQL or MySQL, DuckDB is an embedded analytical engine — its data lives entirely in local files. This means you need to design your own backup strategy, rather than relying on built-in automated backup mechanisms.

DuckDB Backup Architecture Overview

Figure: DuckDB backup architecture — three strategies working together: Snapshots, EXPORT DATABASE, and Compressed Archives

This article systematically covers DuckDB’s three core backup strategies with real-world production scenarios:

  1. Snapshot — Lightweight point-in-time recovery based on WAL
  2. EXPORT DATABASE — Structured SQL script and columnar format export
  3. Compressed Archive — Efficient compression and object storage integration

1. Snapshot: Lightweight Point-in-Time Recovery

1.1 How Snapshots Work

DuckDB’s snapshot feature is based on the Write-Ahead Log (WAL) mechanism. When you execute CREATE SNAPSHOT, DuckDB creates a read-only copy of the current database state. The key advantage is fast creation and low resource consumption, thanks to DuckDB’s Copy-on-Write strategy — only modified data pages are copied.

1.2 Creating and Managing Snapshots

-- Connect to the database
$ duckdb ecommerce.duckdb

-- Create a named snapshot
DuckDB> CREATE SNAPSHOT snap_20260828;
 Snapshot created: snap_20260828

-- List all snapshots
DuckDB> SELECT name, timestamp FROM duckdb_snapshot_order();

┌──────────────────┬─────────────────────┐
 name              timestamp           
├──────────────────┼─────────────────────┤
 snap_20260828     2026-08-28 10:00:00 
 snap_20260821     2026-08-21 10:00:00 
 snap_20260814     2026-08-14 10:00:00 
└──────────────────┴─────────────────────┘

DuckDB Snapshot Management in Terminal

Figure: Terminal operations for creating and managing DuckDB snapshots

1.3 Restoring from Snapshots

When data issues occur, you can restore to a specific point in time:

-- Method 1: Query historical data using AS OF syntax
SELECT * FROM orders AS OF VERSION 42
WHERE created > '2026-08-27';

-- Method 2: Restore an entire table from a snapshot
CREATE TABLE orders_restored AS
SELECT * FROM orders AS OF SNAP 'snap_20260828';

-- Method 3: Attach snapshot as a read-only database
ATTACH 'snap_20260828.duckdb' AS snap_db (READ_ONLY);
SELECT * FROM snap_db.orders WHERE amount > 1000;

1.4 Snapshot Strategy Recommendations

ScenarioFrequencyRetention
Dev/Test environmentDailyLast 7 days
Production (small-scale)Every 6 hoursLast 30 days
Production (large-scale)Weekly full + daily incrementalLast 90 days
-- SQL script for automatic snapshot cleanup
SELECT duckdb_snapshot('snap_' || current_date::TEXT);
-- Create new snapshot before ETL, delete old one after
DROP SNAPSHOT IF EXISTS snap_oldest;

2. EXPORT DATABASE: Structured Full Backup

2.1 Why EXPORT DATABASE?

While snapshots are lightweight, they have limitations:

  • Snapshot files are tightly coupled to DuckDB format — not portable across engines
  • Snapshots consume more space over time (despite CoW, accumulated modifications grow the size)
  • Not suitable for long-term archival or offsite backup

EXPORT DATABASE exports the entire database as standardized SQL scripts or columnar format files, solving these issues.

2.2 Export as SQL Script

-- Export as human-readable SQL script (ideal for version control and review)
EXPORT DATABASE '/backup/ecommerce_sql' (FORMAT CSV);

-- Check the generated files
$ ls -lh /backup/ecommerce_sql/
total 1.2G
-rw-r--r-- 1 user user  45K orders.sql      -- Schema + INSERT statements
-rw-r--r-- 1 user user 890M users.csv       -- User table data
-rw-r--r-- 1 user user 230M products.csv    -- Product table data
-- Export as Parquet columnar format (high compression, ideal for analytics)
EXPORT DATABASE '/backup/ecommerce_parquet' (FORMAT PARQUET);

$ ls -lh /backup/ecommerce_parquet/
total 160M  -- ~60% space savings compared to the original DuckDB file!
-rw-r--r-- 1 user user 128M orders.parquet
-rw-r--r-- 1 user user  30M users.parquet
-rw-r--r-- 1 user user   5M products.parquet

2.4 Restoring from Exported Files

-- Restore from SQL script
$ duckdb restored_db.duckdb
DuckDB> \i /backup/ecommerce_sql/orders.sql;

-- Restore from Parquet (create tables first)
DuckDB> CREATE TABLE orders AS SELECT * FROM read_parquet(['/backup/ecommerce_parquet/orders.parquet']);
DuckDB> CREATE TABLE users AS SELECT * FROM read_parquet(['/backup/ecommerce_parquet/users.parquet']);
DuckDB> CREATE TABLE products AS SELECT * FROM read_parquet(['/backup/ecommerce_parquet/products.parquet']);

3. Compressed Archives and Object Storage Integration

3.1 Exporting to S3/GCS Object Storage

For production environments, storing backups in object storage is best practice. DuckDB’s built-in httpfs extension supports direct export to cloud storage:

-- Configure AWS S3
INSTALL s3;
LOAD s3;
SET s3_region='us-east-1';
SET s3_access_key_id='YOUR_ACCESS_KEY';
SET s3_secret_access_key='YOUR_SECRET_KEY';

-- Export directly to S3
EXPORT DATABASE 's3://my-bucket/backups/ecommerce_20260828'
    (FORMAT PARQUET);

-- Export to Google Cloud Storage
EXPORT DATABASE 'gs://my-bucket/backups/ecommerce_20260828'
    (FORMAT PARQUET);

3.2 Automated Backup Script

#!/bin/bash
# automated_backup.sh — Daily backup script

DB_PATH="/data/ecommerce.duckdb"
BACKUP_DIR="/backup/daily"
DATE=$(date +%Y%m%d)
SNAP_NAME="snap_${DATE}"

# 1. Create snapshot
duckdb "$DB_PATH" -c "CREATE SNAPSHOT '$SNAP_NAME';"

# 2. Export Parquet to backup directory
duckdb "$DB_PATH" -c "EXPORT DATABASE '$BACKUP_DIR/ecommerce_$DATE' (FORMAT PARQUET);"

# 3. Compress backup files
tar czf "$BACKUP_DIR/ecommerce_$DATE.tar.gz" "$BACKUP_DIR/ecommerce_$DATE/"
rm -rf "$BACKUP_DIR/ecommerce_$DATE"

# 4. Upload to S3
aws s3 cp "$BACKUP_DIR/ecommerce_$DATE.tar.gz" \
    "s3://my-bucket/backups/$DATE/"

# 5. Clean up backups older than 30 days
find "$BACKUP_DIR" -name "*.tar.gz" -mtime +30 -delete
find "$DB_PATH.snapshot" -mtime +30 -delete

echo "Backup completed: $DATE"

3.3 Backup Verification and Disaster Recovery Drills

The ultimate purpose of backup is successful recovery when needed. Regular recovery drills are recommended:

-- Verify backup integrity
-- 1. Check row counts match between source and backup
SELECT count(*) FROM read_parquet('/backup/ecommerce_parquet/orders.parquet');
-- Compare with source: SELECT count(*) FROM orders;

-- 2. Check data checksums
SELECT md5(array_agg(order_id::TEXT)) FROM orders;
SELECT md5(array_agg(order_id::TEXT))
FROM read_parquet('/backup/ecommerce_parquet/orders.parquet');

-- 3. Spot-check critical records for completeness and consistency
SELECT * FROM orders AS OF SNAP 'snap_20260828'
WHERE order_id IN (10001, 10002, 10003);

4. Cross-Version Upgrade Strategy

4.1 Smooth Upgrade Process

DuckDB maintains strong backward compatibility, but cross-major-version upgrades require caution:

# Before upgrade: create full backup
duckdb ecommerce.duckdb -c "EXPORT DATABASE '/backup/pre_upgrade' (FORMAT PARQUET);"

# Upgrade DuckDB CLI
# macOS: brew upgrade duckdb
# Linux: wget https://github.com/duckdb/duckdb/releases/download/v1.2.0/duckdb_cli-linux-amd64.zip

# After upgrade: verify data integrity
duckdb ecommerce.duckdb -c "SELECT * FROM duckdb_tables();"
duckdb ecommerce.duckdb -c "SELECT count(*) FROM orders;"

# If issues arise, restore from Parquet backup
duckdb new_db.duckdb -c "CREATE TABLE orders AS SELECT * FROM read_parquet('/backup/pre_upgrade/orders.parquet');"

4.2 Version Compatibility Matrix

Source VersionTarget VersionCompatibilityNotes
0.8.x0.10.x✅ Fully compatibleDirect upgrade works
0.10.x1.x✅ CompatibleRecommend Parquet export backup first
1.x1.x+✅ Fully compatibleSupports in-place upgrade

5. Production Backup Strategy Summary

Combining all three strategies, here’s the recommended production-grade backup plan:

Time GranularityStrategyStorage LocationRetention
HourlySnapshotLocal disk7 days
DailyEXPORT DATABASE (Parquet)Local + S330 days
WeeklyCompressed archive (.tar.gz)S3 Glacier90 days
MonthlyFull export (SQL + Parquet)Offsite backupPermanent
-- One-click full backup workflow
BEGIN;
  CREATE SNAPSHOT snap_$(date +%Y%m%d);
  EXPORT DATABASE 's3://bucket/daily/$(date +%Y%m%d)' (FORMAT PARQUET);
COMMIT;

Conclusion

DuckDB’s backup and migration may require manual design, but this also gives developers great flexibility. By combining snapshots for quick recovery, EXPORT DATABASE for standardized exports, and compressed archives for efficient storage, you can build a comprehensive production-grade data protection system.

For more DuckDB in Action tips, follow DuckDB Lab (duckdblab.org).

📺 Watch video tutorials → Olap Studio YouTube

Subscribe for more DuckDB & AI automation tutorials

Built with Hugo
Theme Stack designed by Jimmy

⚠️ This site is an independent community project, not affiliated with, endorsed by, or sponsored by the DuckDB Foundation or official DuckDB project.

"DuckDB" is a registered trademark of the DuckDB Foundation. This site uses the name solely for factual description purposes.

All content is for educational and community promotion purposes only and does not constitute any commercial service.