Setting up pgblame with Supabase
A 5-minute walkthrough for Supabase users.
1. Enable pg_stat_statements
Supabase has it available but not always enabled by default.
- Open your Supabase project's dashboard.
- Navigate to Database → Extensions.
- Search for
pg_stat_statements. - Toggle it on.
Alternatively, via SQL editor: CREATE EXTENSION IF NOT EXISTS pg_stat_statements; while connected as postgres.
2. Create a read-only role for pgblame
Don't give the agent your superuser credentials. Run this in the SQL editor (connected as postgres):
-- Create the role
CREATE ROLE pgblame_reader WITH LOGIN PASSWORD '<choose-something-strong>';
-- Let it read all query stats. On Supabase the postgres role can't grant
-- pg_read_all_stats directly (it lacks ADMIN option on that role), but it
-- can grant pg_monitor, which includes pg_read_all_stats.
GRANT pg_monitor TO pgblame_reader;
-- On Supabase, pg_stat_statements lives in the "extensions" schema, so the
-- reader needs USAGE on it to see the view.
GRANT USAGE ON SCHEMA extensions TO pgblame_reader;
-- Allow it to connect
GRANT CONNECT ON DATABASE postgres TO pgblame_reader;If you'd like to be even more restrictive, you can revoke its access to the public schema:
REVOKE ALL ON SCHEMA public FROM pgblame_reader;It still works — pgblame only reads pg_stat_statements (in the extensions schema), which the grants above cover.
3. Get the connection string
In Supabase: Settings → Database → Connection pooling, and use the Session mode pooler:
postgresql://pgblame_reader.<project-ref>:<password>@aws-1-<region>.pooler.supabase.com:5432/postgres?sslmode=requireTwo Supabase-specific gotchas, both easy to miss:
- The pooler username is your role plus your project ref:
pgblame_reader.<project-ref>— not justpgblame_reader. - Use the pooler host (
aws-1-<region>.pooler.supabase.com), not the directdb.<ref>.supabase.cohost — the direct host is IPv6-only and usually unreachable from outside Supabase. Copy the exact host and region from the dashboard.
4. Get a project token from pgblame
In your pgblame dashboard:
- Click New project.
- Name it (e.g. "myapp-prod").
- The wizard runs a connection test against your Postgres, then issues a one-time token like
pgb_xxxxxxxx. Copy it now; it's shown once.
5. Run the agent
Mount a volume at the agent's data dir so its local buffer survives restarts:
docker run -d \
--name pgblame-agent \
--restart unless-stopped \
-e PGBLAME_DATABASE_URL="postgresql://pgblame_reader.<ref>:...@aws-1-<region>.pooler.supabase.com:5432/postgres?sslmode=require" \
-e PGBLAME_TOKEN="pgb_xxxxxxxx" \
-v pgblame-data:/home/nonroot/.pgblame \
ghcr.io/liberzon/pgblame-agent:latestIt'll start sending data within 60–120 seconds (the first tick is a baseline; the second emits deltas).
6. Wire deploy webhooks
You probably deploy via Vercel or Railway. See:
Troubleshooting
| Symptom | Likely cause |
|---|---|
pg_stat_statements does not exist | Extension not enabled; go to step 1. |
permission denied for view pg_stat_statements | Skipped step 2, or the role lacks pg_monitor / USAGE on the extensions schema. |
connection refused / connection times out | You're likely using the direct db.<ref>.supabase.co host, which is IPv6-only and usually unreachable. Use the Session-mode pooler host (aws-1-<region>.pooler.supabase.com:5432). |
password authentication failed | Typo in the password, or the pooler username is missing the project ref — it must be pgblame_reader.<project-ref>. |
| No data after 5 minutes | Check docker logs pgblame-agent. The agent's error_log SQLite table at /home/nonroot/.pgblame/agent.db has details. |