npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

pgpulse

v1.0.2

Published

Real-time PostgreSQL monitoring TUI (top/htop for Postgres)

Readme

pgpulse

A terminal-based live monitoring tool for PostgreSQL (similar to top / htop). It periodically reads pg_stat_activity, pg_stat_statements, locks, and table/index summaries with low overhead; for pg_stat_statements it diffs against the previous snapshot and keeps a 5-slot ring buffer (default 2s interval) for the last 10-second activity window.

Example (ASCII)

The TUI is a fixed grid: each box is fed by a specific catalog / view (or a join built on them). Roughly:

| Screen region | PostgreSQL source | What you are looking at | |---------------|-------------------|-------------------------| | Live queries (top-left) | pg_stat_activity | One row per backend on the current DB: pid, user, age, state, truncated query, wait info. | | Top queries (top-right) | pg_stat_statements (extension) | Aggregated statement stats: calls, total/mean time, rows, buffer hits — sortable; d toggles cumulative vs last 10s delta window. | | Locks / blocking (middle) | pg_locks + pg_stat_activity | Blocked vs blocking pid, wait time, relation, snippet of the blocked query. | | Tables / indexes (strip) | pg_stat_user_tables + pg_stat_user_indexes | High seq_scan tables; unused index candidates (idx_scan = 0 among top candidates). | | Footer | — | Global keybindings (q, r, s, /, …). |

Typical layout (colors omitted; narrow terminals may wrap lines):

  [ top-left: live sessions ]          [ top-right: statement stats ]
┌─ live queries (pg_stat_activity) ────────┐┌─ top queries [cum sort:total_exec_time] ─┐
│ 1842  app     1.2s    active   SELECT …  ││ calls 12400 total 890.1ms mean 0.07ms | …  │
│ 1845  app     12.4s   active   UPDATE …   ││ calls 2100  total 120.5ms mean 0.06ms | …  │
│ 1901  report  0.3s    idle     COMMIT …   ││ calls 980   total 45.2ms  mean 0.05ms | …  │
│ ...                                       ││ ...                                          │
└──────────────────────────────────────────┘└──────────────────────────────────────────────┘
  [ middle: who blocks whom ]
┌─ locks / blocking ────────────────────────────────────────────────────────────────────────┐
│ 1842 ← 1903  wait  3.2s  public.orders  │  SELECT * FROM orders WHERE …                 │
│ (no blocking pairs)                                                                      │
└──────────────────────────────────────────────────────────────────────────────────────────┘
  [ bottom strip: table + index health snapshot ]
┌─ tables / indexes ────────────────────────────────────────────────────────────────────────┐
│ tables  public.orders:seq=12000  public.users:seq=800 ...                                  │
│ unused idx  public.idx_foo_created(idx_scan=0)  ...                                      │
└──────────────────────────────────────────────────────────────────────────────────────────┘
 q quit  r resetΔ  s sort(tot)  d delta(cum)  / filter  l locked  i idle-tx  tab focus …

Requirements

  • Node.js 18+ (LTS recommended)
  • PostgreSQL 10+ recommended (earlier versions are untested). On connect, the client reads current_setting('server_version_num') and picks SQL accordingly:
    • pg_stat_activity: backend_type is selected only on PG10+; older servers use NULL for that column.
    • pg_stat_statements: PG13+ uses total_exec_time / mean_exec_time; PG12 and older use total_time / mean_time (still exposed in the UI as total_exec_time / mean_exec_time via aliases).
  • Optional: pg_stat_statements extension (for the Top Queries panel)
CREATE EXTENSION IF NOT EXISTS pg_stat_statements;

Installation

npm install

If you install better-sqlite3 for optional local snapshot history, you can use --sqlite (requires a native build).

Development

Unit tests use Vitest. Test files live next to sources: src/**/*.test.js.

npm test          # run once
npm run test:watch   # watch mode

Configuration: vitest.config.js (environment: node, include: src/**/*.test.js). Pure helpers (utils, engine/delta, SQL builders) are covered; TUI and live DB access are not.

Running

npm start

or

node src/index.js

After a global install: pgpulse (see package.json bin).

Connection

Precedence order:

  1. DATABASE_URL
  2. --connection-string
  3. PGHOST, PGPORT, PGUSER, PGPASSWORD, PGDATABASE and optional flags: --host, --port, --user, --password, --database

Examples:

DATABASE_URL=postgres://user:pass@localhost:5432/mydb npm start
node src/index.js --host localhost --port 5432 --user postgres --database app

Options

| Flag | Description | |------|----------------| | --interval <ms> | Refresh interval (default 2000) | | --long-threshold <s> | Long-query threshold; yellow/red highlighting (default 5) | | --export <file> | Default path for export when using e | | --sqlite <file> | Optional SQLite snapshot history | | -h, --help | Help |

Keyboard

| Key | Action | |-----|--------| | q | Quit | | Tab | Focus panels (activity / statements / locks) | | r | Reset delta baseline and 10s window | | s | Sort: total_exec_timemean_exec_timecalls | | d | Toggle cumulative vs last 10s delta window | | / | Text filter (Enter to apply, Esc to cancel) | | l | Show only backends involved in locks | | i | Show only idle in transaction | | Enter | Full query text for selection (activity / statements) | | t | Table analysis: pick a user table (high seq_scan sample), then per-table index list + heap/cache stats | | x | EXPLAIN on selected statement (confirm) | | k | pg_terminate_backend (confirm) | | e | Export JSON (--export or timestamped file) |

Architecture (summary)

  • src/collectors/*: Each runs focused/optimized SQL and returns normalized JSON.
  • src/engine/snapshot.js: Merges all collector output.
  • src/engine/delta.js: pg_stat_statements deltas keyed by userid:dbid:queryid plus a 10s ring.
  • src/ui/layout.js: neo-blessed grid, modals, global shortcuts.
  • t table analysis: list of hot tables (pg_stat_user_tables + pg_statio_user_tables + size); Enter loads that table’s indexes from pg_stat_user_indexes on demand.
  • Footer (2nd line): PostgreSQL server snapshot (via SQL): buffer cache hit % (pg_stat_database blks_hit/read), sessions vs max_connections, shared_buffers / work_mem (from pg_settings), deadlocks, temp_files, checkpoint pressure hint (pg_stat_bgwriter). This is not the OS process CPU% or total server RAM — those require OS/agent metrics outside PostgreSQL.

Security notes

  • EXPLAIN and pg_terminate_backend require sufficient privileges; use carefully in production.
  • Long query text is truncated in the UI; the modal shows the full text.

License

MIT