pgblame

How to enable pg_stat_statements in Postgres

Add pg_stat_statements to shared_preload_libraries in postgresql.conf, restart Postgres, then run CREATE EXTENSION IF NOT EXISTS pg_stat_statements. On managed Postgres (Supabase, Neon, RDS) the library is already preloaded, so you only run the CREATE EXTENSION step.

pg_stat_statements is the Postgres extension that tracks execution stats for every (normalized) query your database runs — call counts, total and mean execution time, rows. It's the foundation of almost every Postgres performance tool, including pgblame. Here's how to turn it on.

Self-hosted Postgres

1. Preload the library

pg_stat_statements must be loaded at server start, so add it to shared_preload_libraries in postgresql.conf:

# postgresql.conf
shared_preload_libraries = 'pg_stat_statements'

If you already have other libraries listed, append it comma-separated: 'pg_cron,pg_stat_statements'.

2. Restart Postgres

shared_preload_libraries is only read at startup, so a reload isn't enough — restart the server:

sudo systemctl restart postgresql

3. Create the extension

Connect as a superuser and register it in the database you want to monitor:

CREATE EXTENSION IF NOT EXISTS pg_stat_statements;

4. Verify it's collecting

SELECT count(*) FROM pg_stat_statements;
-- a growing number of rows = it's working

Managed Postgres (Supabase, Neon, RDS)

Managed providers already preload the library — you don't edit postgresql.conf or restart. You only run the CREATE EXTENSION step (and on some platforms, toggle it in a UI):

  • SupabaseDatabase → Extensions, search pg_stat_statements, toggle on. Note it lives in the extensions schema. See Supabase query performance.
  • Neon — run CREATE EXTENSION IF NOT EXISTS pg_stat_statements; in the SQL editor; it's preloaded on every branch.
  • Amazon RDS / Aurora — it's in the default parameter group's shared_preload_libraries; if you use a custom parameter group, add it there, then CREATE EXTENSION.

Reading the slowest queries

Once it's collecting, your top queries by cumulative cost:

SELECT
  query,
  calls,
  round(mean_exec_time::numeric, 1) AS avg_ms,
  round(total_exec_time::numeric, 0) AS total_ms
FROM pg_stat_statements
ORDER BY total_exec_time DESC
LIMIT 20;
The manual ceiling

pg_stat_statements only knows totals since the last reset. Run that query today and you see what's slow now — but not whether a query got slower last Tuesday, or which deploy did it. The view has no time dimension. To answer "which deploy slowed this?", something has to snapshot these numbers on a schedule and line them up against your releases.

That's the job pgblame automates: it reads pg_stat_statements every 60 seconds and correlates the deltas with your Vercel/Railway/GitHub Actions deploys, so a regression points straight at the release that caused it. If you'd rather not pay $149/mo for that, it's the indie-priced alternative to pganalyze.

See which deploy slowed your Postgres — free, no card.

Start free — no card

FAQ

Does enabling pg_stat_statements require a restart?
Only on self-hosted Postgres, and only the first time — because shared_preload_libraries is read at startup. On managed Postgres (Supabase, Neon, RDS) the library is already preloaded, so CREATE EXTENSION alone is enough and needs no restart.
Is pg_stat_statements safe to run in production?
Yes. It's the standard query-stats extension, used everywhere. Overhead is low and bounded by pg_stat_statements.max (default 5000 tracked statements). It records query shape and timing, not row data.
Why is pg_stat_statements empty after enabling it?
Either the library wasn't preloaded (so the extension is installed but collecting nothing — check shared_preload_libraries and restart), or no queries have run since the last reset. It only tracks normalized statements executed after it loaded.
Does it track every query?
It tracks normalized statements (literals stripped) up to pg_stat_statements.max distinct entries. Beyond that, the least-used entries are evicted, so very high-cardinality workloads may not capture everything.

Related

How to enable pg_stat_statements in Postgres