How to Manually Back Up a Supabase Database

Automatic backups are convenient, but there are still times when creating a manual Supabase backup makes sense.
Maybe you are about to run a database migration. Perhaps you want an extra copy before importing thousands of records. Or maybe you are using the Supabase Free plan and want to keep your own database backups.
Whatever the reason, Supabase gives you a straightforward way to create a logical database backup using its CLI.
In this guide, we will create a manual Supabase backup containing your database roles, schema, and data, then look at where to store it and what the backup does not include.
If you are using the Free plan specifically, you may also want to read How to Back Up Supabase on the Free Plan.
What Does a Manual Supabase Backup Include?
A Supabase project runs on PostgreSQL.
When you create a logical backup, you are essentially exporting the parts of PostgreSQL that you may need later to recreate your database.
For a useful manual backup, you should normally save three things:
- Database roles
- Database schema
- Database data
The schema contains things such as your tables, columns, functions, policies, indexes, and relationships.
The data export contains the actual records inside your tables.
Keeping these separately makes the backup easier to understand and restore.
Before You Start
You will need:
- Supabase CLI
- Docker
- Your Supabase database connection string
- Your database password
- A secure folder for the backup
Open your Supabase project and use the Connect option to find your database connection details.
For this type of backup operation, the Session pooler connection is usually the easiest option.
Your connection string will look similar to:
postgresql://postgres.PROJECT_REF:PASSWORD@HOST:5432/postgres
Be careful with this value.
It contains credentials that can provide database access. Do not put it in frontend code, screenshots, public repositories, or blog examples using your real project details.
A cleaner option is to store it temporarily in an environment variable:
export SUPABASE_DB_URL="your-connection-string"
Now your commands can use $SUPABASE_DB_URL without repeatedly exposing the full connection string.
Step 1: Back Up Database Roles
Start by exporting your database roles:
supabase db dump \
--db-url "$SUPABASE_DB_URL" \
-f roles.sql \
--role-only
This creates:
roles.sql
Roles control database-level permissions and can matter when moving or recovering a project.
If you have created custom roles with login access, remember that passwords may require separate handling during recovery.
Step 2: Back Up the Database Schema
Next, export the database structure:
supabase db dump \
--db-url "$SUPABASE_DB_URL" \
-f schema.sql
This creates:
schema.sql
Your schema describes how the database is built.
It can include your:
- Tables
- Columns
- Relationships
- Indexes
- Functions
- Triggers
- Row Level Security policies
- Other database objects
A schema backup is useful, but it does not contain all of your application records.
That is why you need the next step.
Step 3: Back Up Your Data
Now export the actual table data:
supabase db dump \
--db-url "$SUPABASE_DB_URL" \
-f data.sql \
--use-copy \
--data-only \
-x "storage.buckets_vectors" \
-x "storage.vector_indexes"
This creates:
data.sql
At this point, your backup folder should look something like:
supabase-backup/
├── roles.sql
├── schema.sql
└── data.sql
You now have a logical database backup that can be used later as part of a restore or migration process.
If you want a deeper explanation of the different export formats, see How to Export a Supabase Database.
Name Your Backup Properly
Do not leave your backup folder named simply:
backup
After a few months, you will have no idea which project or date it belongs to.
Use something clear:
my-saas-production-2026-08-09/
├── roles.sql
├── schema.sql
└── data.sql
If the backup was created before a migration, make that clear too:
my-saas-production-before-billing-migration-2026-08-09/
Good naming sounds like a small detail until you are trying to recover production data under pressure.
Where Should You Store the Backup?
Do not keep the only copy on your development computer.
If your laptop fails, gets lost, or the folder is accidentally deleted, your backup disappears with it.
Keep another copy somewhere separate.
For example:
- Google Drive
- Private cloud storage
- Secure backup server
- Client-controlled storage for agency projects
For small SaaS teams, Google Drive is often practical because the files remain easy to locate and manage.
The important idea is off-site backup: your backup should not exist only in the same place as the system you are trying to protect.
What a Supabase Database Backup Does Not Protect
This is one of the most important things to understand.
Your database dump does not contain the actual files stored inside Supabase Storage.
Imagine your database contains:
invoices/customer-583.pdf
The database backup may preserve information related to that file.
But the actual PDF stored in the bucket is separate.
The same applies to:
- User avatars
- Product images
- Documents
- Videos
- CSV files
- Customer uploads
- Generated reports
If your app depends on Storage, use a separate Storage backup process. We covered that in How to Back Up Supabase Storage Files.
A complete Supabase recovery strategy should therefore consider both the PostgreSQL database and Storage objects.
When Should You Create a Manual Backup?
Manual backups are especially useful before risky changes.
Create one before:
- Large database migrations
- Bulk updates
- Large imports
- Deleting columns or tables
- Changing billing data
- Restructuring relationships
- Moving to another Supabase project
- Testing destructive scripts
Imagine your automatic backup ran at midnight, but you are running a migration at 5 PM.
A fresh manual backup gives you a much closer recovery point than yesterday’s backup.
This is why manual backups can still be useful even when automatic backups are enabled.
Should Manual Backups Be Your Main Strategy?
For a development project, manual backups may be enough.
For a production SaaS app, relying only on manual backups becomes risky.
The reason is simple:
You eventually forget.
You may create backups regularly for the first month, then become busy with features, customer support, deployments, and bug fixes.
Suddenly your “latest” backup is three weeks old.
A better production strategy is:
Automatic backups for regular protection + manual backups before risky changes.
You can read Manual vs Automatic Database Backups for a full comparison.
SupaBackup handles the automatic side by creating scheduled Supabase database backups and saving them to your own Google Drive.
That removes the need to remember the CLI process every week.
Test Your Manual Backup Once
Do not assume a backup is usable simply because the three files exist.
At least once, test the restore process in a safe environment.
Use:
- A local PostgreSQL database
- A staging environment
- A separate Supabase test project
Check that your important tables, records, functions, and policies are available.
This is particularly important before relying on the process for a production application.
A backup you have successfully restored is far more valuable than a folder you have never tested.
Final Thoughts
Creating a manual Supabase backup is straightforward once you understand the three main exports:
roles.sql for roles,
schema.sql for database structure,
data.sql for your actual records.
Manual backups are especially useful before migrations, imports, bulk updates, and other risky database changes.
Just remember their main weakness: someone has to remember to create them.
For an important production project, use automatic backups as your regular protection and create manual backups when you need an extra recovery point.
SupaBackup can automate your Supabase database backups and send them directly to your own Google Drive, while the manual CLI process remains useful whenever you want an immediate copy before making a major change.
The best backup is not simply the one you create.
It is the one you can find and restore when something actually goes wrong.


