pgblame

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=require

Two Supabase-specific gotchas, both easy to miss:

  • The pooler username is your role plus your project ref: pgblame_reader.<project-ref> — not just pgblame_reader.
  • Use the pooler host (aws-1-<region>.pooler.supabase.com), not the direct db.<ref>.supabase.co host — 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:latest

It'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

SymptomLikely cause
pg_stat_statements does not existExtension not enabled; go to step 1.
permission denied for view pg_stat_statementsSkipped step 2, or the role lacks pg_monitor / USAGE on the extensions schema.
connection refused / connection times outYou'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 failedTypo in the password, or the pooler username is missing the project ref — it must be pgblame_reader.<project-ref>.
No data after 5 minutesCheck docker logs pgblame-agent. The agent's error_log SQLite table at /home/nonroot/.pgblame/agent.db has details.
Docs — pgblame