# Example: scheduled Supabase backup with backupdrill. # # HOW TO USE # 1. Copy this file into your OWN repo at .github/workflows/scheduled-backup.yml # 2. Add the repo secrets listed below (Settings → Secrets and variables → Actions). # 3. That's it — it runs daily, and you can also trigger it by hand from the # Actions tab ("Run workflow"). # # REQUIRED SECRETS (database backup) # BACKUPDRILL_DATABASE_URL Supabase Session Pooler connection string # (dashboard: Connect → Session pooler). # The default postgres user works as-is; a # read-only role usually fails under RLS — # see the README's connection-string section. # BACKUPDRILL_S3_BUCKET Destination bucket you own (S3 / R2 / B2). # BACKUPDRILL_S3_ACCESS_KEY_ID Credentials for that destination bucket. # BACKUPDRILL_S3_SECRET_ACCESS_KEY # # OPTIONAL SECRETS # BACKUPDRILL_S3_ENDPOINT Set for R2/B2/self-hosted; omit for AWS S3. # BACKUPDRILL_S3_REGION Bucket region ("auto" works for R2). # BACKUPDRILL_PROJECT_NAME Readable name used in object keys/manifest. # BACKUPDRILL_PING_URL A Healthchecks.io check's ping URL. The backup # pings it when it starts, finishes or fails, so # you hear about a failed or skipped run. # # To also back up Supabase Storage FILES (not just the DB), set all four: # BACKUPDRILL_SUPABASE_STORAGE_ENDPOINT # BACKUPDRILL_SUPABASE_STORAGE_REGION # BACKUPDRILL_SUPABASE_STORAGE_ACCESS_KEY_ID # BACKUPDRILL_SUPABASE_STORAGE_SECRET_ACCESS_KEY # (generate the keys in Dashboard → Storage → Settings → S3 Access Keys) # # Unset optional secrets resolve to an empty string, which backupdrill treats # as "not provided" — so leaving them out simply backs up the database only. # # COST NOTE: a backup is egress on YOUR Supabase bill. Read the README's # "Egress & cost" section before switching this to a daily schedule on a large DB. name: scheduled-backup on: schedule: # Daily at 03:00 UTC. Adjust or switch to weekly (e.g. '0 3 * * 0') as your # data grows — see the README on egress cost. - cron: "0 3 * * *" workflow_dispatch: {} # allow manual runs from the Actions tab # Read-only checkout is all this job needs. permissions: contents: read # Never let two backups overlap (avoids double egress if one run is slow). concurrency: group: backupdrill-scheduled cancel-in-progress: false jobs: backup: runs-on: ubuntu-latest steps: # pg_dump's major version must be >= your Supabase Postgres version. # Supabase runs PG 17, so install postgresql-client-17 from the official # PostgreSQL apt repo (PGDG); Ubuntu's default repo lags behind. - name: Install postgresql-client-17 (PGDG) run: | sudo install -d /usr/share/postgresql-common/pgdg curl -fsSL https://www.postgresql.org/media/keys/ACCC4CF8.asc \ | sudo gpg --dearmor -o /usr/share/postgresql-common/pgdg/apt.postgresql.org.gpg echo "deb [signed-by=/usr/share/postgresql-common/pgdg/apt.postgresql.org.gpg] \ https://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" \ | sudo tee /etc/apt/sources.list.d/pgdg.list sudo apt-get update sudo apt-get install -y postgresql-client-17 # Point the CLI straight at the v17 binary so it can't pick up an older # pg_dump that may already be on the runner's PATH. - name: Tell backupdrill where pg_dump 17 lives run: echo "BACKUPDRILL_PG_DUMP=/usr/lib/postgresql/17/bin/pg_dump" >> "$GITHUB_ENV" - name: Set up Node 20 uses: actions/setup-node@v4 with: node-version: "20" - name: Run backupdrill run: npx backupdrill backup env: # --- required --- BACKUPDRILL_DATABASE_URL: ${{ secrets.BACKUPDRILL_DATABASE_URL }} BACKUPDRILL_S3_BUCKET: ${{ secrets.BACKUPDRILL_S3_BUCKET }} BACKUPDRILL_S3_ACCESS_KEY_ID: ${{ secrets.BACKUPDRILL_S3_ACCESS_KEY_ID }} BACKUPDRILL_S3_SECRET_ACCESS_KEY: ${{ secrets.BACKUPDRILL_S3_SECRET_ACCESS_KEY }} # --- optional: destination bucket --- BACKUPDRILL_S3_ENDPOINT: ${{ secrets.BACKUPDRILL_S3_ENDPOINT }} BACKUPDRILL_S3_REGION: ${{ secrets.BACKUPDRILL_S3_REGION }} BACKUPDRILL_PROJECT_NAME: ${{ secrets.BACKUPDRILL_PROJECT_NAME }} # --- optional: also back up Supabase Storage files (set all four) --- BACKUPDRILL_SUPABASE_STORAGE_ENDPOINT: ${{ secrets.BACKUPDRILL_SUPABASE_STORAGE_ENDPOINT }} BACKUPDRILL_SUPABASE_STORAGE_REGION: ${{ secrets.BACKUPDRILL_SUPABASE_STORAGE_REGION }} BACKUPDRILL_SUPABASE_STORAGE_ACCESS_KEY_ID: ${{ secrets.BACKUPDRILL_SUPABASE_STORAGE_ACCESS_KEY_ID }} BACKUPDRILL_SUPABASE_STORAGE_SECRET_ACCESS_KEY: ${{ secrets.BACKUPDRILL_SUPABASE_STORAGE_SECRET_ACCESS_KEY }} # --- optional: Healthchecks.io monitoring --- BACKUPDRILL_PING_URL: ${{ secrets.BACKUPDRILL_PING_URL }}