Automatically backup your Zotero library to Git, with hourly backups and cross-device synchronization.
This backup system consists of the following key files:
backup.sh- The main backup script that handles the entire backup process.gitignore- Specifies which files should be excluded from backup (styles, translators, etc.)README.md- This documentation file
You'll need to create these files during setup:
~/Library/LaunchAgents/com.user.zoterobck.plist- LaunchAgent configuration for automatic hourly backups
~/.config/systemd/user/zoterobck.service- Systemd service definition~/.config/systemd/user/zoterobck.timer- Systemd timer for hourly execution
The backup system automatically includes:
zotero.sqlite- Your main Zotero database (split into parts for Git)better-bibtex.sqlite- Better BibTeX plugin databasestorage/- All your PDFs, notes, and attachmentsaria/- AI assistant messages and data- Configuration files and other data files
The .gitignore file excludes:
- System files (
.DS_Store) - Zotero's built-in styles and translators (updated by Zotero itself)
- Temporary files and signatures
- Search engine icons
- Creates hourly backups of your entire Zotero library
- Backs up all your PDFs, notes, and database
- Works across multiple computers
- Smart process handling with notifications
- Keeps a complete history of all your changes
- Automatically manages conflicts and file locks
- Create a Git repository on GitHub/GitLab to store your backups
- Open Terminal and go to your Zotero folder:
cd ~/Zotero
- Set up Git in your Zotero folder:
git init git remote add origin your-repository-url
- Set up SSH keys for GitHub/GitLab if you haven't already
The backup system is already set up in this repository! The key files are:
backup.sh- Already executable and ready to use.gitignore- Already configured to backup the right filesREADME.md- This documentation
You don't need to download anything additional - just proceed to Step 3 to set up automatic backups.
-
Create the required files:
mkdir -p ~/Library/LaunchAgents touch ~/Library/LaunchAgents/com.user.zoterobck.plist
-
Copy this content to
~/Library/LaunchAgents/com.user.zoterobck.plist(replace YOUR_USERNAME with your actual username):<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>Label</key> <string>com.user.zoterobck</string> <key>ProgramArguments</key> <array> <string>/bin/sh</string> <string>/Users/YOUR_USERNAME/Zotero/backup.sh</string> </array> <key>WorkingDirectory</key> <string>/Users/YOUR_USERNAME/Zotero</string> <key>StartInterval</key> <integer>3600</integer> <key>RunAtLoad</key> <true/> <key>StandardErrorPath</key> <string>/Users/YOUR_USERNAME/Library/Logs/zoterobck.err</string> <key>StandardOutPath</key> <string>/Users/YOUR_USERNAME/Library/Logs/zoterobck.out</string> </dict> </plist>
Important: Make sure the path
/Users/YOUR_USERNAME/Zotero/backup.shpoints to the actual location of thebackup.shfile in this repository. -
Set file permissions and start the backup service:
chmod 644 ~/Library/LaunchAgents/com.user.zoterobck.plist launchctl load ~/Library/LaunchAgents/com.user.zoterobck.plist
-
Copy the service files:
mkdir -p ~/.config/systemd/user cp zoterobck.service ~/.config/systemd/user/ cp zoterobck.timer ~/.config/systemd/user/
-
Start the backup service:
systemctl --user enable zoterobck.timer systemctl --user start zoterobck.timer
The backup.sh script is the heart of this backup system. Here's what it does:
- Zotero Detection: Checks if Zotero is running before starting backup
- Automatic Waiting: Waits up to 3 attempts (20 seconds each) for you to close Zotero
- Notifications: Sends system notifications about backup status
- Process Safety: Waits 5 seconds after Zotero closes to ensure files are released
- Large File Management: Splits
zotero.sqliteinto 25MB parts for Git compatibility - Smart Cleanup: Removes temporary
.partfiles after successful backup - Lock File System: Prevents multiple backup processes from running simultaneously
- Automatic Recovery: Removes stale lock files after 1 hour timeout
- Conflict Resolution: Automatically handles merge conflicts with remote repository
- Smart Commits: Only commits when there are actual changes
- Document Tracking: Logs which PDFs and documents were added/modified
- Push Safety: Only removes temporary files after successful Git push
- macOS: Uses
osascriptfor native notifications andpgrepfor process detection - Linux: Uses
notify-sendfor notifications and appropriate process management
The backup script now includes smart process management:
- When a backup starts, it checks if Zotero is running
- If Zotero is running:
- You'll receive a "Zotero Backup: Waiting" notification
- The script will wait up to 3 times (with 20-second intervals)
- After Zotero closes, it waits an additional 5 seconds for files to be released
- If Zotero doesn't close after maximum attempts:
- The backup is cancelled
- You'll receive a "Backup cancelled" notification
- The backup will try again in the next cycle
To prevent backup conflicts:
- A lock file is created during backup
- Lock files expire after 1 hour to prevent stuck backups
- All temporary files are automatically cleaned up
- Multiple backup attempts cannot run simultaneously
The script manages several types of files:
- zotero.sqlite: The main database file
- zotero.sqlite.bak:
- Created by Zotero for safety
- Left untouched by the backup script
- Managed by Zotero itself
- zotero.sqlite.part*:
- Created temporarily during backup
- Automatically cleaned up after successful backup
- Used to handle large database files in Git
The script now handles conflicts more gracefully:
- First attempts a fast-forward pull
- If that fails, tries auto-merge favoring local changes
- If conflicts still occur:
- Notifies you to close Zotero
- Preserves your local changes
- Will retry in the next backup cycle
# Check if service is running (should show a number)
launchctl list | grep zoterobck
# View backup logs
tail -f ~/Library/Logs/zoterobck.out# Check service status
systemctl --user status zoterobck.timer
# View backup logs
journalctl -u zoterobck.service --user -f- Save your work in Zotero
- Close Zotero completely
- The backup will proceed automatically
- You can reopen Zotero after seeing "Backup completed successfully"
- Close Zotero
- Run the backup manually:
cd ~/Zotero ./backup.sh
- Wait for completion before reopening Zotero
- Check file paths: Make sure paths in your
.plist(macOS) or.service(Linux) files match your actual username and the location ofbackup.sh - Verify backup.sh is executable: Run
ls -la backup.shto confirm it has execute permissions - Test the script manually: Run
./backup.shfrom your Zotero directory to test - Try restarting the service:
# macOS launchctl unload ~/Library/LaunchAgents/com.user.zoterobck.plist launchctl load ~/Library/LaunchAgents/com.user.zoterobck.plist # Linux systemctl --user restart zoterobck.timer
If you're missing files or having permission issues:
# Check if backup.sh exists and is executable
ls -la ~/Zotero/backup.sh
# Make it executable if needed
chmod +x ~/Zotero/backup.sh
# Check if .gitignore exists
ls -la ~/Zotero/.gitignore
# Verify your plist file (macOS only)
ls -la ~/Library/LaunchAgents/com.user.zoterobck.plist- Get the latest backup from your Git repository
- In Terminal, go to your Zotero folder and run:
cd ~/Zotero cat zotero.sqlite.part* > zotero.sqlite
Need help? Open an issue on GitHub.