pgProofGet early access

Guide

Backing up a Supabase Free-plan project

The Free plan includes zero backups, and idle projects are paused after about a week. If your side project has real users, its only protection is the one you build.

What you're working with

The manual routine

Use the Session Pooler connection (IPv4, port 5432 — why):

# 1. Schema + data, custom format (compressed, restorable per-table)
pg_dump -Fc -f "backup-$(date +%F).dump" \
  "postgresql://postgres.<REF>:<PWD>@aws-0-<REGION>.pooler.supabase.com:5432/postgres"

# 2. Roles (grants live in the dump; role definitions do not)
pg_dumpall --roles-only --no-role-passwords -f roles.sql \
  -d "postgresql://postgres.<REF>:<PWD>@aws-0-<REGION>.pooler.supabase.com:5432/postgres"

What is and isn't inside that dump:

Schedule it

A GitHub Actions cron is the zero-infrastructure option (runners are IPv4-only, which is exactly why you need the pooler string):

on:
  schedule: [{cron: "0 3 * * *"}]
jobs:
  backup:
    runs-on: ubuntu-latest
    steps:
      - run: sudo apt-get install -y postgresql-client-17
      - run: pg_dump -Fc -f backup.dump "${{ secrets.SUPABASE_SESSION_POOLER_URL }}"
      - run: # push backup.dump to your S3/R2 bucket, encrypted

The step everyone skips

A cron that runs is not a backup that restores. Truncated dumps, missing extensions, and version mismatches all produce dumps that look fine in the bucket and fail the night you need them. Restore-test at least monthly: the 5-step drill.

Or make all of this one click

pgProof runs the schedule, includes roles, RLS and auth users, encrypts with your key, and restore-tests every single backup. Free tier for one project — built exactly for free-plan Supabase.

Join the early-access waitlist