A transparent PostgreSQL proxy for developers. Point your app at pgspy instead of your real database and get a live terminal dashboard of every query, its duration, and automatic N+1 warnings — with zero code changes.
┌─ pgspy ─────────────────────────────────────────────────────────────┐
│ pgspy 127.0.0.1:15432 → 127.0.0.1:5432 connections: 2 │
├─────────────────────────────────────────────────────────────────────┤
│ # │ Time │ Dur │ Conn │ Flag │ Query │
│ 42 │ 14:23:15.001 │ 2ms │ #0 │ │ SELECT * FROM u │
│ 43 │ 14:23:15.003 │ 1ms │ #0 │ N+1 x3 │ SELECT * FROM p │
│ 44 │ 14:23:15.004 │ 1ms │ #0 │ N+1 x4 │ SELECT * FROM p │
│ 45 │ 14:23:15.183 │ 87ms │ #1 │ │ SELECT count(*) │
├─────────────────────────────────────────────────────────────────────┤
│ avg 22.8ms total 4560ms N+1 warnings: 2 │
└─────────────────────────────────────────────────────────────────────┘
ORM-heavy applications silently generate N+1 queries that tank performance under real load. Framework-specific tools (Rails Bullet, Django Debug Toolbar) don't help if you use Prisma, Sequelize, SQLAlchemy, JOOQ, or raw queries. pgspy works at the TCP level — it is language- and framework-agnostic.
npm install -g pgspyOr run directly without installing:
npx pgspyStart pgspy:
pgspy --listen 127.0.0.1:15432 --upstream 127.0.0.1:5432Then change your DATABASE_URL to use port 15432:
# Before
DATABASE_URL=postgresql://user:pass@localhost:5432/mydb
# After
DATABASE_URL=postgresql://user:pass@localhost:15432/mydb
Your app connects through pgspy transparently. The TUI opens automatically.
| Flag | Default | Description |
|---|---|---|
--listen |
127.0.0.1:15432 |
Address pgspy listens on |
--upstream |
127.0.0.1:5432 |
Real PostgreSQL address |
| Key | Action |
|---|---|
q / Ctrl+C |
Quit |
j / ↓ |
Scroll down |
k / ↑ |
Scroll up |
G / End |
Jump to newest query |
g / Home |
Jump to oldest query |
c |
Clear query list |
pgspy normalizes each query by replacing all literal values (strings, numbers) with placeholders and groups identical patterns within a 500 ms window. If the same normalized query appears 3 or more times, it is flagged as an N+1 pattern and all matching queries are highlighted.
Example: these three queries are all SELECT * FROM posts WHERE user_id = ? and trigger a warning:
SELECT * FROM posts WHERE user_id = 1
SELECT * FROM posts WHERE user_id = 2
SELECT * FROM posts WHERE user_id = 3| Color | Meaning |
|---|---|
| Green | < 20ms |
| Yellow | 20–99ms |
| Red | ≥ 100ms |
pgspy handles both the simple query protocol (Q messages) and the extended query protocol (P — Parse messages), so it works with prepared statements and connection poolers like PgBouncer.
SSL connections: pgspy intercepts SSLRequest and responds with N (no SSL), then continues in plaintext. This is intentional for local development. Do not use pgspy in production.
MIT