This guide covers database operations, schema management, and data maintenance for Tome.
Tome uses two SQLite databases:
- Tome Database (
data/tome.db): Your reading progress, sessions, and streaks - Calibre Database (read-only): Your book metadata from Calibre
This guide focuses on managing the Tome database.
Migrations create and update the database schema. They must be run before first use.
# Run all pending migrations
bun run db:migrate
# Or use the script directly
bun run lib/db/migrate.tsWhen to run:
- First-time setup
- After pulling updates that change the schema
- When you see "table not found" errors
Migration behavior:
- Development: Must be run manually
- Testing: Runs automatically in test setup
- Docker: Runs automatically on container startup
After modifying the database schema in lib/db/schema.ts:
# Generate migration from schema changes
bun run db:generateThis creates a new migration file in drizzle/ directory with SQL statements to update the schema.
For rapid development iteration, you can push schema changes directly:
# Push schema directly without creating migration
bun run db:pushWARNING: This bypasses the migration system. Only use in development. Never use in production.
Drizzle Studio provides a visual database browser:
# Open Drizzle Studio in browser
bun run db:studioAccess at https://local.drizzle.studio to browse tables, view data, and run queries.
Tome includes built-in backup scripts with timestamped files.
# Create backup with timestamp
bun run db:backup
# Example output: data/backups/tome.db.backup-20251127_143055Backup location: data/backups/ directory
Automatic backups: Docker migrations create automatic backups before schema changes
# List all available backups with size and timestamp
bun run db:list-backups# Interactive restore (select from list)
bun run db:restore
# Or manually copy backup
cp data/backups/tome.db.backup-YYYYMMDD_HHMMSS data/tome.dbImportant: Restore stops the application during the process.
Recommended backup practices:
- Before migrations: Always backup before running migrations
- Regular schedule: Weekly automated backups
- Before updates: Backup before pulling application updates
- Before experiments: Backup before testing new features
# Example backup script (add to cron)
#!/bin/bash
cd /path/to/tome
bun run db:backup
# Keep last 10 backups
ls -t data/backups/*.backup-* | tail -n +11 | xargs rm -fCached book metadata from Calibre with additional tracking fields.
Key fields:
id: Book ID (from Calibre)title,author_sort: Book metadatapath,has_cover: File informationlastSynced: Timestamp of last Calibre syncisOrphan: True if book removed from Calibre
Source: Synced from Calibre's metadata.db
Tracks each read-through of a book.
Key fields:
id: Unique session IDbookId: Reference to bookstatus:to-read,read-next,reading,readrating: 0-5 stars (synced with Calibre)review: Text reviewstartedDate,completedDate: Session datesisArchived: True for old sessions (when re-reading)
Notes:
- Users can have multiple sessions per book (re-reading)
- Only one active session per book
- Previous sessions archived automatically
Historical log of reading progress within sessions.
Key fields:
id: Unique log entry IDsessionId: Reference to sessioncurrentPage: Page number (if page-based tracking)percentage: Progress percentage (0-100)readAt: Timestamp of progress entrynotes: Optional notes about reading session
Notes:
- Immutable once created (never updated)
- Supports backdated entries
- Multiple entries per day allowed
Tracks reading streak data per user.
Key fields:
userId: User identifiercurrentStreak: Current consecutive dayslongestStreak: All-time recordlastActivityDate: Last day with progress entrytotalDaysActive: Total days with any readingdailyGoalPages: User's daily page goal
Notes:
- Streak breaks on missed days
- Calculated based on progress log entries
- Supports configurable daily goals
# View migration history
sqlite3 data/tome.db "SELECT * FROM __drizzle_migrations"
# Check database size
ls -lh data/tome.db
# Check table row counts
sqlite3 data/tome.db "
SELECT 'books' as table_name, COUNT(*) as count FROM books
UNION ALL
SELECT 'reading_sessions', COUNT(*) FROM reading_sessions
UNION ALL
SELECT 'progress_logs', COUNT(*) FROM progress_logs
UNION ALL
SELECT 'streaks', COUNT(*) FROM streaks;
"# Check for corruption
sqlite3 data/tome.db "PRAGMA integrity_check;"
# Should output: okSQLite databases can become fragmented over time:
# Vacuum database to reclaim space and optimize
sqlite3 data/tome.db "VACUUM;"
# Analyze query performance
sqlite3 data/tome.db "ANALYZE;"WARNING: This deletes all reading progress, sessions, and streaks.
# Delete database
rm data/tome.db
# Recreate schema
bun run db:migrateAlternative: Keep database but clear specific tables:
sqlite3 data/tome.db "
DELETE FROM progress_logs;
DELETE FROM reading_sessions;
DELETE FROM streaks;
-- Books table keeps Calibre sync
"Migrations are SQL files that update the database schema incrementally.
Migration files: Stored in drizzle/ directory
Tracking: __drizzle_migrations table tracks which migrations have been applied
Execution order: Migrations run in chronological order based on filename timestamps
-
File-Based Locking:
- Lock file:
data/.migration.lock - Prevents concurrent migrations
- Auto-timeout: 5 minutes for stale locks
- Lock file:
-
Pre-Flight Checks:
- Data directory writable
- Migration files present
- Database permissions correct
- Sufficient disk space
-
Automatic Backups (Docker only):
- Created before each migration
- Timestamped format
- Keeps last 3 backups
- Stored in
data/backups/
-
Retry Logic (Docker only):
- 3 retry attempts
- Exponential backoff: 5s, 10s, 20s
- Detailed logging
# Check if migrations are needed
sqlite3 data/tome.db "
SELECT hash, created_at
FROM __drizzle_migrations
ORDER BY created_at DESC
LIMIT 5;
"
# View pending migrations
ls -la drizzle/
# Force migration (bypass safety checks)
# WARNING: Use only if you know what you're doing
rm data/.migration.lock
bun run lib/db/migrate.tsDrizzle doesn't provide automatic rollback. To undo a migration:
-
Restore from backup:
bun run db:restore
-
Or manually reverse changes:
- Review migration SQL in
drizzle/ - Write inverse SQL statements
- Apply manually via sqlite3
- Review migration SQL in
-
Or reset and rebuild:
rm data/tome.db bun run db:migrate # Re-sync Calibre and re-enter progress (data loss)
# Export entire database to SQL
sqlite3 data/tome.db .dump > tome-export.sql
# Export specific table
sqlite3 data/tome.db "SELECT * FROM progress_logs" > progress-export.csv
# Export as JSON (requires jq)
sqlite3 -json data/tome.db "SELECT * FROM reading_sessions" | jq '.' > sessions.json# Import from SQL dump
sqlite3 data/tome.db < tome-export.sql
# Import CSV into table
sqlite3 data/tome.db <<EOF
.mode csv
.import data.csv table_name
EOF# Open interactive shell
sqlite3 data/tome.db
# Example queries
sqlite> SELECT COUNT(*) FROM books;
sqlite> SELECT title, rating FROM books WHERE rating >= 4;
sqlite> SELECT * FROM reading_sessions WHERE status = 'reading';
sqlite> .exitAll database commands work inside Docker containers:
# Run migrations
docker exec tome bun run lib/db/migrate.ts
# Create backup
docker exec tome bun run db:backup
# List backups
docker exec tome bun run db:list-backups
# Restore (interactive)
docker exec -it tome bun run db:restore
# Open database shell
docker exec -it tome sqlite3 /app/data/tome.db
# Check database status
docker exec tome sqlite3 /app/data/tome.db "PRAGMA integrity_check;"For database-related issues, see TROUBLESHOOTING.md:
- Database not found
- Migration failures
- Corruption recovery
- Permission errors
- Lock file issues
- Backup before changes: Always backup before migrations or major operations
- Regular integrity checks: Run monthly integrity checks
- Monitor size: Track database growth over time
- Vacuum periodically: Optimize database quarterly
- Test migrations: Test migrations in development before production
- Keep backups: Maintain at least 3 recent backups
- Use migrations: Never modify schema manually in production
- Document changes: Comment complex migrations
- Drizzle ORM Documentation
- SQLite Documentation
- ARCHITECTURE.md - System architecture details
- DEPLOYMENT.md - Production deployment guide