pg_dump + GitHub Actions: the free way, and the 5 things it misses
A DIY Supabase backup with pg_dump and GitHub Actions is a great start. But at 2 AM during a real disaster, here are the 5 critical things it misses — and how Supakeep fills the gaps.

The DIY Backup That Most Developers Build
If you search "supabase backup github actions" on Google, you'll find dozens of tutorials, GitHub Marketplace actions, and Reddit threads showing how to run pg_dump on a cron schedule for free. Supabase even has an official guide for it.
The setup looks something like this:
name: Daily Supabase Backup
on:
schedule:
- cron: '0 2 * * *'
jobs:
backup:
runs-on: ubuntu-latest
steps:
- name: Dump database
run: |
PGPASSWORD=${{ secrets.SUPABASE_DB_PASSWORD }} \
pg_dump -h db.abc.supabase.co -U postgres \
-F c -f backup.dump
- name: Commit to repo
run: git add backup.dump && git commit -m "Daily backup"It's free. It runs on a schedule. It feels like you've solved the backup problem.
And honestly — it's a great start. If you're doing this, you're already ahead of teams with no backup at all. But at 2 AM on a Saturday when your production database is gone and you need to restore right now, you'll discover that pg_dump alone leaves five critical gaps.
Source: [Supabase Docs — Automated backups using GitHub Actions](https://supabase.com/docs/guides/deployment/ci/backups), [GitHub Marketplace — supa-backup](https://github.com/marketplace/actions/supa-backup)
| pg_dump + Actions | Supakeep | |
|---|---|---|
| Postgres tables & data | ||
| Storage objects (user uploads) | ||
| Auth users & sessions | ||
| Edge Functions | ||
| Off-site, outside your vendor | ||
| Restore tested & monitored |
Miss #1: Storage Objects Are Invisible to pg_dump
This is the most common surprise. Your Supabase project has two types of data:
- 1Postgres database — tables, rows, schemas, functions. pg_dump handles this.
- 2Storage objects — user uploads, images, documents in your Supabase Storage buckets. pg_dump does NOT handle this.
(Backups and replication are not the same thing either — worth knowing before you rely on one.) Storage objects live in S3-compatible object storage, not in Postgres. When you run pg_dump, your backup file contains zero bytes of your users' uploaded files. If a user uploaded 10,000 profile photos to your storage bucket, those files simply don't exist in your backup.
At 2 AM when you restore from your pg_dump backup, the database tables come back — but every storage URL returns a 404. User avatars, uploaded documents, generated PDFs — all gone.
Supabase's own CLI documentation acknowledges this: pg_dump runs with flags to exclude managed schemas including storage. You need a separate process to back up storage objects via the S3-compatible API.
How Supakeep handles this: Supakeep backs up both database AND storage in the same job. The dashboard shows separate backup artifacts — db_2026-07.sql.gz for the database and storage_2026-07.tar for your storage buckets. Both land in your Google Drive.
Source: [SimpleBackups — How to Restore Supabase Storage Objects](https://simplebackups.com/blog/restore-supabase-storage-objects), [Supabase CLI Reference](https://supabase.com/docs/reference/cli/introduction)
Miss #2: Role Chaos — pg_dump Doesn't Export Global Roles
Supabase relies on a set of predefined Postgres roles that form the backbone of its security model:
anon— unauthenticated requestsauthenticated— logged-in usersservice_role— privileged server-side accesspostgres— the superuser
Standard pg_dump does not export these global roles. Exporting roles requires pg_dumpall --roles-only, which is often restricted on managed database platforms like Supabase.
The Supabase GitHub Actions guide tries to work around this by dumping roles separately, but many managed Postgres providers restrict access to the system catalogs needed for role exports. The result: your backup contains all your data and schemas, but not the role hierarchy that makes it all work.
How Supakeep handles this: Supakeep captures the complete Supabase project state — database, auth data, and role configuration — as separate backup artifacts. The auth_2026-w28.json.gz file in your Google Drive contains the auth state that standard pg_dump skips.
Source: [Supabase Docs — Postgres Roles](https://supabase.com/docs/guides/database/postgres/roles), [Supabase Blog — Postgres Roles and Privileges](https://supabase.com/blog/postgres-roles-and-privileges)
Miss #3: RLS Policies Break Without the Right Roles
This is where miss #2 becomes dangerous. Row-Level Security (RLS) policies in Supabase are written directly against those roles:
CREATE POLICY "Users can read own posts"
ON posts
FOR SELECT
USING (auth.uid() = user_id);This policy assumes the authenticated role exists and that auth.uid() works. If you restore your database to a fresh Supabase project where the role hierarchy doesn't match, one of two things happens:
- 1Fail open — RLS policies can't evaluate because the roles don't exist. In some configurations, this means the table returns all rows to all users. That's a security breach.
- 2Fail closed — RLS policies block everything. Every query returns an error. Your app is down.
Neither outcome is acceptable at 2 AM during a disaster recovery.
The Supabase community forums are full of developers hitting this exact problem: restoring a pg_dump backup to a new project and finding that RLS policies fail because the role configuration doesn't carry over.
How Supakeep handles this: Because Supakeep captures auth data and edge functions alongside the database dump, the restore process includes the role and auth configuration that RLS depends on. See our database security guide for a deep dive on RLS and roles.
Source: [Supabase Docs — Row Level Security](https://supabase.com/docs/guides/database/postgres/row-level-security), [DesignRevision — Supabase RLS Guide 2026](https://designrevision.com/blog/supabase-row-level-security)
Miss #4: Secrets Living in CI/CD
To run pg_dump in GitHub Actions, you need to put your PostgreSQL connection string — containing the database password with full access — into a GitHub secret.
This means your highly privileged database credentials are now stored in a third-party CI/CD system. While GitHub encrypts secrets at rest, this still expands your attack surface:
- 1Any GitHub Action with
secretsaccess can read the connection string. - 2Forked PRs can sometimes trigger workflows that access secrets (depending on your configuration).
- 3A compromised GitHub token or action dependency can exfiltrate the secret.
- 4Audit logs show that a secret was accessed, but not which step read it.
For a side project, this risk is acceptable. For a growing SaaS handling user data, it's a vulnerability you need to acknowledge.
How Supakeep handles this: Supakeep uses OAuth to connect to your Google Drive with least-privilege scope — it can only see files it creates, not your entire Drive. Your Supabase connection is established through Supakeep's dashboard, not stored in a CI system. The zero-retention architecture means your data flows through Supakeep but is never persisted there.
Miss #5: No Verification — A .sql File Is a Hope, Not a Backup
The most dangerous gap is the one you don't know about. A .sql or .dump file sitting in a GitHub repository is not a verified backup — it's an untested artifact.
Without a restore drill, you have no way to know:
- Does the backup file open without errors?
- Do all foreign key constraints restore correctly?
- Are all RLS policies intact?
- Is the schema complete or were some objects silently skipped?
- Does the data actually load into a fresh database?
A GitHub Actions workflow that runs pg_dump and commits the file gives you a green checkmark. That checkmark means "pg_dump ran without errors" — not "the backup can be restored." These are very different things.
Compliance frameworks like SOC 2 and ISO 27001 require documented restore testing evidence. A cron job that creates files doesn't produce that evidence — you do, by manually running a restore and screenshotting the results.
How Supakeep handles this: Supakeep's dashboard shows clear run status for every backup job — success, failure, and error messages. You can see exactly when each backup ran and whether it captured all components (database, storage, auth, edge functions). Combined with our step-by-step restore guide, you have everything you need to perform and document a verified restore.
Source: [Konfirmity — SOC 2 Backup And Recovery](https://www.konfirmity.com/blog/soc-2-backup-and-recovery-for-soc-2), [Supakeep — Restore Guide](https://supakeep.io/blog/restore-supabase-from-backup)
DIY pg_dump + GitHub Actions vs Supakeep:
pg_dump approach: Supakeep approach:
+---------------+ +---------------+
| Supabase DB | | Supabase DB |
+---------------+ +---------------+
| |
v v
+---------------+ +---------------+
| GitHub Actions | | Supakeep API |
| (cron trigger) | | (zero retention)|
+---------------+ +---------------+
| |
v v
+---------------+ +---------------+
| .dump file in | | Google Drive |
| GitHub repo | | (your storage) |
+---------------+ +---------------+
| |
What's MISSING: What's INCLUDED:
x Storage objects [x] Database dump
x Auth data [x] Storage objects
x Edge functions [x] Auth data
x Role hierarchy [x] Edge functions
x Restore testing [x] Role hierarchy
x Off-site storage [x] Run status dashboard
[x] Off-site (your Drive)The Full Comparison
- 1
Find the artifact
pg_dump: dig through commit history for the last good dump. Supakeep: pick the dated backup in the dashboard.
- 2
Restore the database
Both work — this is the part pg_dump does well.
- 3
Restore user uploads
pg_dump: nothing to restore, the files were never captured. Supakeep: storage artifact restores alongside.
- 4
Get auth and roles back
pg_dump: roles were often skipped, RLS can fail open. Supakeep: auth and roles captured as their own artifact.
- 5
Prove it worked
pg_dump: manual spot checks. Supakeep: run log plus a documented restore procedure.
| What You Need | pg_dump + GitHub Actions | Supakeep |
|---|---|---|
| Database backup | Yes (pg_dump) | Yes (daily/weekly/monthly) |
| Storage objects | No — invisible to pg_dump | Yes — backed up as separate artifact |
| Auth data | Partial — roles often restricted | Yes — captured as separate artifact |
| Edge functions | No | Yes — backed up as separate artifact |
| Role hierarchy | Often missing | Yes — auth and roles captured |
| RLS policy integrity | Risk of fail open/closed on restore | Roles and auth preserved |
| Credential exposure | DB password in GitHub secrets | OAuth + least-privilege, no DB password in CI |
| Off-site storage | GitHub repo (same vendor as CI) | Your own Google Drive (different vendor) |
| Run status visibility | GitHub Actions logs | Dedicated dashboard with run status |
| Restore testing | Manual — your responsibility | Documented restore guide + verified artifacts |
| Setup time | 1-2 hours of YAML and secrets | 20 seconds via OAuth |
| Cost | Free (GitHub Actions minutes) | Free during beta |
When pg_dump + GitHub Actions Is the Right Choice
To be clear — the DIY approach isn't wrong. It's a legitimate choice when:
- 1You're running a side project with no user uploads
- 2You don't use RLS or custom roles
- 3You're comfortable managing GitHub secrets
- 4You can accept the risk of untested backups
- 5You don't need compliance evidence
For a hobby project or a proof of concept, pg_dump in GitHub Actions is fine.
When It's Time to Upgrade
The moment any of these becomes true, you've outgrown the DIY approach:
- 1Users are uploading files to your Supabase Storage
- 2You're using RLS policies (and you should be)
- 3You're handling user data that matters
- 4A customer or partner is asking about your backup strategy
- 5You need SOC 2 or ISO 27001 compliance evidence
- 6You'd rather spend your time building features than maintaining backup scripts
That's when Supakeep fills the gaps — storage objects, auth data, edge functions, role integrity, credential safety, and verified restore — in 20 seconds, for free.
Next: read the Supabase backup best practices for small teams, or walk through how to restore a Supabase project from a SQL backup.
Frequently asked questions
For a simple project with no storage uploads and no RLS, pg_dump covers the database. For anything with user-uploaded files, RLS policies, or compliance requirements, pg_dump alone misses critical components. See the article above for the five specific gaps.
Technically yes, but you'd need to write a separate script that uses the S3-compatible API to download all objects from every bucket, zip them, and commit them. Most DIY tutorials skip this step entirely. Supakeep handles storage backups automatically.
Supakeep captures database, storage, auth, and edge functions as separate backup artifacts. The database component uses pg_dump with the appropriate flags for Supabase's managed schemas, while storage and auth are captured through their respective APIs.
GitHub Actions will show a red X in the workflow run, but it won't alert you unless you set up notifications. Many developers discover failed backups only when they need to restore and find the last successful backup was weeks ago. Supakeep's dashboard shows run status for every job in real time.
GitHub encrypts secrets at rest and in transit, but any action with secrets access can read them. For a side project, the risk is manageable. For a SaaS handling user data, expanding your credential exposure to a third-party CI system is a risk worth considering. Supakeep uses OAuth and never requires your database password in a CI system.
Download the backup file, create a fresh Supabase project, and run psql with the file. Check that all tables, RLS policies, and roles are intact. See our [restore guide](https://supakeep.io/blog/restore-supabase-from-backup) for a step-by-step walkthrough.
Edge functions are TypeScript functions deployed to Supabase's edge runtime. They're not stored in Postgres and aren't captured by pg_dump. If you lose your edge functions, your API endpoints go down. Supakeep captures them as a separate artifact.
Absolutely. Defense in depth is never a bad idea. Run pg_dump in GitHub Actions as a secondary backup, and use Supakeep as your primary off-site backup with storage, auth, and edge function coverage.
Sources & further reading
- 1Automated backups using GitHub ActionsSupabase Docssupabase.com
- 2supa-backupGitHub Marketplacegithub.com
- 3Postgres RolesSupabase Docssupabase.com
- 4Row Level SecuritySupabase Docssupabase.com
- 5Postgres Roles and PrivilegesSupabase Blogsupabase.com
- 6How to Restore Supabase Storage ObjectsSimpleBackupssimplebackups.com
- 7Supabase CLI ReferenceSupabase CLI Referencesupabase.com
- 8Supabase RLS Guide 2026DesignRevisiondesignrevision.com
- 9SOC 2 Backup And RecoveryKonfirmitykonfirmity.com
- 10I Didn't Want to Pay for Supabase Backups, So I Built My OwnMediummedium.com
- 11I built a free daily Supabase backup workflowRedditreddit.com
- 12Backups without supabase-cliSupabase Discussionsgithub.com