Functions and production

Observe, back up, and recover

Monitor database and platform signals, understand backup coverage, rehearse restore, check current limits, and keep provider-independent exports.

A production project you cannot observe or restore is a countdown. Set up both before the first real user signs up, while mistakes are still free.

Watch what predicts trouble

Keep an eye on errors, slow queries, connection count, Auth failures, function logs, Storage failures, Realtime behavior, and usage limits. The dashboard’s Reports and Logs pages cover most of it. For query time, the pg_stat_statements extension is already enabled, so you can ask Postgres directly:

select calls, round(mean_exec_time) as avg_ms, query
from pg_stat_statements
order by mean_exec_time desc
limit 5;

That gives you the five slowest queries on average, with how often each one ran. Run it once a week and you’ll spot the missing index before your users do.

Tie alerts to things users feel. “Connections near the limit” and “Auth error rate climbing” deserve a notification. A dashboard where every moving number alerts trains you to ignore all of it, which is worse than no alerts.

Know what a backup covers

Hosted projects on paid plans get scheduled database backups. Point-in-time recovery is available as an add-on when your acceptable data loss is minutes rather than a day. Read your current plan’s coverage and retention instead of assuming. Limits change, and the moment to discover yours is not during an incident.

A database backup does not mean everything is recoverable. Uploaded files live in object storage, and the database only holds their metadata. If losing user uploads is unacceptable, keep exports or replication for those buckets too. The same goes for anything in an external service.

Keep one provider-independent export in the rotation:

supabase db dump -f prod-2026-08-03.sql
# Dumping schemas from remote database...

That file is plain SQL. It restores into any PostgreSQL anywhere, which is the exit you hope never to need and should have anyway.

The drill is the proof

A backup you never restored is a hope, not a backup. Restore a disposable backup or dump into a separate project, never over production. Then point a copy of the application at it and check the things that break quietly: Auth-linked ownership, Storage files, and one complete workflow end to end, sign-in included.

The ownership check is one query:

select count(*) from notes
where user_id not in (select id from auth.users);
-- 0

Anything other than zero means notes point at users that don’t exist in the restored auth schema.

That is the failure you are hunting. A restore brings back your tables but not the auth data they reference, and every user_id points at nobody. Counts match, rows look fine, and no user can see their own data. Finding that in a drill costs an afternoon. Finding it in production costs you users.

Put the drill on the calendar. Once a quarter is enough for most projects, and it is the only way to know the plan works.

Lesson completed