pgcheckup
For teams on Supabase, Neon & RDS without a DBA

Grade your Postgres.
Get the fix, in plain English.

Run one read-only script, paste the output, and get a graded performance audit with copy-paste index & config fixes — each one explained, each one backed by before/after benchmark proof. Not another wall of raw metrics.

No signup · No connection string · Read-only by design

1

Run the collector

Download one read-only SQL script. It reads only catalog & statistics views — never your data. Review it, then run it with psql.

2

Paste the output

Upload the JSON it produces. It's analyzed on the spot — we don't store it, and it contains no rows from your tables.

3

Apply the fixes

Get a letter grade, ranked findings, and copy-paste SQL for each — missing indexes, unindexed FKs, bloat, config, N+1s.

A real report, start to finish

This is the actual output of the grader on a typical struggling production database. Every finding below is generated by the same engine your scan uses.

F
5/100Postgres 15.6 (Supabase)

At risk — 2 serious issues need attention before they bite.

4 tables3 indexes4 queriescache hit 95.7%9.1 GB on disk
2High8Medium5Low

15 findings

This table is large and is read with full sequential scans far more often than via an index. Each scan reads every row. A WHERE/JOIN/ORDER BY column here almost certainly needs an index. Run EXPLAIN (ANALYZE, BUFFERS) on the queries hitting it to find the predicate.

seq_scan = 24,500idx_scan = 1,200rows read sequentially = 410,000,000,000
Fix · Identify the filtered/joined column from EXPLAIN and add a B-tree index. Use CREATE INDEX CONCURRENTLY in production to avoid locking writes.
-- find the column from EXPLAIN, then:
CREATE INDEX CONCURRENTLY idx_events_<column>
  ON public.events (<column>);

Expected win: Targeted index turns full scans into index lookups — often 10–100× faster.

shared_buffers is still at (or below) the 128MB install default. That default is intentionally tiny so Postgres starts anywhere; it is not a production value. On a dedicated database, 25% of RAM is the standard starting point.

shared_buffers = 128 MBrecommended = 25% of RAM
Fix · Set shared_buffers to ~25% of system RAM and restart Postgres.
ALTER SYSTEM SET shared_buffers = '2GB';  -- ≈25% of RAM
-- restart required

Expected win: More data cached in Postgres → fewer disk reads across the board.

Plain-English remediation

Every finding says what's wrong, why it costs you, and the exact SQL to fix it — written for engineers, not DBAs.

Before / after proof

Paid scans benchmark the slow query, apply the fix on a shadow copy, and show you the real speedup. No guessing.

Catches the silent killers

Unindexed foreign keys, dead-tuple bloat, untuned random_page_cost on SSD, N+1 patterns — the things that quietly add latency.

Read-only & private

We never ask for your connection string on the free tier. The collector reads only statistics. Your data never leaves your box.

Built for Supabase / Neon / RDS

Tuned for managed Postgres defaults — where shared_buffers and random_page_cost are usually wrong out of the box.

Weekly monitoring (Pro)

Re-grade on a schedule, get regression alerts when a deploy slows a query, and track which fixes you've shipped.

Start free. Upgrade when it pays for itself.

The one-time audit is free, forever. Pro adds weekly monitoring, regression alerts, and before/after benchmarks for ₹1,999 / $29 a month.