A comprehensive bash script to backup your remote Supabase instance, including database schemas, data, RLS policies, functions, storage metadata, and more.
Tested Environment: This script has been developed and tested with self-hosted Supabase instances running on Coolify (local/VPS deployments).
Cloud Supabase Compatibility: While the script should work with official Supabase Cloud instances, it has not been tested in that environment. If you're using Supabase Cloud:
- Connection methods may differ
 - Direct database access might be restricted
 - SSH tunneling might not be available
 - Some features may not work as expected
 
Use at your own risk and please test with non-critical data first. Contributions and feedback from cloud users are welcome!
- Complete Database Backup: Backs up all schemas (public, auth, storage)
 - Multiple Formats: Creates both custom binary dump and human-readable SQL files
 - RLS Policies: Exports Row Level Security policies
 - Functions & Procedures: Backs up all custom functions and stored procedures
 - Storage Metadata: Saves storage bucket configurations
 - SSH Tunnel Support: Secure connection through SSH tunnel
 - Automatic Compression: Creates compressed archives (tar.gz or zip)
 - Restore Capability: Easy restoration from backups
 - Cross-Platform: Works on macOS, Linux, and Windows (Git Bash/Cygwin)
 
- 
PostgreSQL Client Tools (pg_dump, psql, pg_restore)
- macOS: 
brew install postgresql@15 - Ubuntu/Debian: 
sudo apt-get install postgresql-client - Fedora/CentOS: 
sudo yum install postgresql - Windows: Download from postgresql.org
 
 - macOS: 
 - 
curl (for Storage API calls)
- Usually pre-installed on macOS/Linux
 - Windows: Included in Git Bash
 
 - 
SSH access (optional, only if using SSH tunnel)
 
- Database credentials (host, port, database name, user, password)
 - Supabase project URL
 - Service role key (for Storage backup)
 - SSH access to server (if using SSH tunnel)
 
- 
Clone or download this repository
git clone https://github.com/ykarateke/supabase-backup-script.git cd supabase-backup-script - 
Make the script executable
chmod +x supabase-backup.sh
 - 
Create your configuration file
cp config.sh.example config.sh
 - 
Edit config.sh with your settings
nano config.sh
or use your favorite text editor.
 
Edit config.sh and fill in your Supabase details:
# For direct connection: use your server IP
DB_HOST="your-server-ip"
# For SSH tunnel: use "localhost" after tunnel is established
# DB_HOST="localhost"
DB_PORT="5432"
DB_NAME="postgres"
DB_USER="postgres"
DB_PASSWORD="your-database-password"Get these from your Supabase project settings (Settings → API):
SUPABASE_URL="https://your-project-id.supabase.co"
SUPABASE_SERVICE_KEY="your-service-role-key"Only required if connecting through SSH tunnel:
SSH_HOST="your-server-ip"
SSH_USER="root"
POSTGRES_INTERNAL_IP="10.0.0.1"  # Internal PostgreSQL IP from docker networkTo find your PostgreSQL internal IP:
ssh root@your-server-ip
docker inspect supabase-db | grep IPAddressUncomment the appropriate line in config.sh:
# macOS Intel:
export PATH="/usr/local/opt/postgresql@15/bin:$PATH"
# macOS Apple Silicon:
export PATH="/opt/homebrew/opt/postgresql@15/bin:$PATH"./supabase-backup.shThis will:
- Connect to your Supabase database (via SSH tunnel if configured)
 - Create timestamped backup directory
 - Export database, schemas, policies, functions, and metadata
 - Compress everything into a tar.gz archive
 - Open the backup folder automatically
 
./supabase-backup.sh testTests database connectivity without performing backup.
./supabase-backup.sh restore /path/to/backup/full_backup.dump./supabase-backup.sh helpsupabase_backups/
├── YYYYMMDD_HHMMSS/
│   ├── database/
│   │   ├── full_backup.dump      # Binary format (for pg_restore)
│   │   └── full_backup.sql       # SQL format (human-readable)
│   ├── migrations/
│   │   └── schema.sql            # Schema structure only
│   ├── metadata/
│   │   ├── policies.sql          # RLS policies
│   │   ├── functions.sql         # Custom functions
│   │   ├── tables.txt            # Table list
│   │   └── indexes.txt           # Index list
│   ├── storage/
│   │   └── buckets.json          # Storage bucket config
│   └── logs/
│       └── database_backup.log   # Detailed backup log
└── supabase_backup_YYYYMMDD_HHMMSS.tar.gz  # Compressed archive
Simplest method if your database is publicly accessible:
# In config.sh:
DB_HOST="your-server-ip"  # or your-database-host.com
DB_PORT="5432"More secure, connects through SSH:
# In config.sh:
DB_HOST="your-server-ip"  # Initially set to server IP
SSH_HOST="your-server-ip"
SSH_USER="root"
POSTGRES_INTERNAL_IP="10.0.0.1"  # Found via: docker inspect supabase-dbThe script will automatically:
- Create SSH tunnel on port 5432
 - Switch DB_HOST to localhost
 - Connect through the tunnel
 - Close tunnel when done
 
Set up tunnel manually before running script:
# In terminal 1: Create tunnel
ssh -L 5432:10.0.0.1:5432 root@your-server-ip
# In terminal 2: Run backup
# In config.sh set:
DB_HOST="localhost"
# Leave SSH settings empty
./supabase-backup.shTo run automatic backups, add to crontab:
# Edit crontab
crontab -e
# Add line for daily backup at 2 AM:
0 2 * * * /path/to/supabase-backup/supabase-backup.sh >> /path/to/supabase-backup/cron.log 2>&1
# Or weekly on Sundays at 3 AM:
0 3 * * 0 /path/to/supabase-backup/supabase-backup.sh >> /path/to/supabase-backup/cron.log 2>&1For macOS, you may need to use launchd instead of cron.
Install PostgreSQL client tools:
- macOS: 
brew install postgresql@15 - Linux: 
sudo apt-get install postgresql-client 
- Check your credentials in 
config.sh - Test connection: 
./supabase-backup.sh test - Verify database host is accessible: 
ping your-database-host - Check firewall settings allow port 5432
 
- Test SSH manually: 
ssh root@your-server-ip - Ensure you can connect without script
 - Check SSH_HOST, SSH_USER in config.sh
 - Verify SSH key is set up or you can enter password
 
- Verify SUPABASE_URL in config.sh
 - Check SUPABASE_SERVICE_KEY is correct
 - Ensure service role key has proper permissions
 
Make script executable:
chmod +x supabase-backup.shCreate config file:
cp config.sh.example config.sh
nano config.sh- Never commit config.sh to version control - It contains sensitive credentials
 - Use .gitignore to exclude config.sh and backups
 - Restrict file permissions:
chmod 600 config.sh # Only owner can read/write - Store backups securely - Encrypt or move to secure location
 - Use SSH tunnel instead of direct connection when possible
 - Rotate service role keys periodically
 - Keep backup files encrypted if storing long-term
 
- All tables and data in 
public,auth, andstorageschemas - Table structures and relationships
 - Row Level Security (RLS) policies
 - Custom functions and stored procedures
 - Triggers
 - Indexes
 - Sequences
 - Storage bucket configurations
 - Database roles and permissions (structure only)
 
- Actual storage files (images, documents, etc.) - only bucket metadata
 - System tables and PostgreSQL internals
 - Realtime subscriptions
 - Edge Functions code
 - Environment variables
 
- 
Create new Supabase project
 - 
Update config.sh with new project credentials
 - 
Restore database structure and data:
./supabase-backup.sh restore /path/to/backup/full_backup.dump
 - 
Manually recreate:
- Storage buckets (use 
storage/buckets.jsonas reference) - Edge Functions
 - Environment variables
 - API keys and secrets
 
 - Storage buckets (use 
 
Contributions are welcome! Please feel free to submit a Pull Request.
MIT License - feel free to use and modify as needed.
If you encounter issues:
- Check the troubleshooting section above
 - Review logs in 
supabase_backups/[timestamp]/logs/ - Open an issue with error details
 
- Initial release
 - Database backup with multiple formats
 - RLS policies and functions export
 - Storage metadata backup
 - SSH tunnel support
 - Cross-platform compatibility
 - Automatic compression
 - Restore functionality