pgmon
A PostgreSQL monitoring TUI inspired by pg_activity.
Features
- Real-time views of:
pg_stat_activitypg_stat_replication/pg_replication_slotspg_stat_databasepg_lockspg_stat_io(PostgreSQL 16+)pg_stat_statements(if extension exists)
- Pg-activity-inspired
Activitydashboard with sampled TPS/DML/temp rates, session counts, and worker/process summaries - Activity subviews for active, waiting, blocking, and idle in transaction backends
- Contextual in-app help overlay (
?) with current-view shortcuts and metric explanations - Built-in themes plus runtime theme switching and config validation with
pgmon check-config - Interactive TUI (Tabs, Table navigation)
- Configurable refresh rate and top-N rows.
Installation
Usage
# Connect using an alias from pgmon.yaml or pgmon.yml
# Load a specific config file
# Use the config's default connection
# Validate config loading and connection resolution without starting the TUI
# Specific home view and sort
# Fail faster on unreachable hosts
# Save selected queries into a persistent directory
# Or rely on PGMON_DSN / ~/.pgpass
PGMON_DSN="postgresql://postgres@localhost/postgres"
Configuration
pgmon supports a pgmon.yaml or pgmon.yml configuration file for connection aliases, UI preferences, built-in theme selection, custom named themes, and per-view colors.
If the config file does not define any connections, pgmon still starts normally and falls back to PGMON_DSN, then .pgpass.
The file is looked for in the following locations (in order):
- Path passed with
-c, --config - Current working directory (
./pgmon.yaml, then./pgmon.yml) - User's configuration directory (
~/.config/pgmon/pgmon.yaml, then~/.config/pgmon/pgmon.ymlon Linux/macOS)
An example config is available at the repository root as pgmon.yaml.
Example pgmon.yaml
# Optional default alias used when no positional alias is passed
default_connection: local
# Optional theme selection
# Built-in themes: calibrachoa, sky, mint, retro
theme: my_theme
# Named connections
connections:
local:
dsn: "postgresql://postgres:postgres@localhost:5432/postgres"
prod:
dsn: "postgresql://pgmon@prod.example.com/postgres"
staging:
dsn: "host=staging-db dbname=postgres user=pgmon password=secret"
# Optional custom theme templates
themes:
my_theme:
ui:
header_border_color: "#95a8b8"
footer_border_color: "#98aaa4"
views:
settings:
colors:
value: "#b4a9b7"
# Global UI preferences
# Top-level values override the selected theme
ui:
show_controls: true # Set to false to hide the Controls section
default_export_format: "csv" # or "json"
# Customize UI colors for specific views
# Top-level values override the selected theme
views:
settings:
colors:
value: "#a8a0b4" # Optional muted override for the 'Value' column
Built-in themes are available even without a config file: calibrachoa, sky, mint, and retro. Colors can be specified by name (e.g., "red", "green", "blue", "yellow", "cyan", "magenta", "white", "black") or as #RRGGBB hex values for softer palettes. The my_theme example above is only illustrative; you can remove it entirely and select a built-in theme by name.
Connection aliases are selected with pgmon <alias>. If default_connection is set, pgmon can start without a positional alias and will use that configured target. If --dsn is also provided, the explicit DSN takes precedence over both the positional alias and default_connection.
Current config support is limited to the keys above; PGMON_DSN_* environment switching remains future work.
When themes are available, press T inside the TUI to switch between them at runtime. Theme switching is applied immediately for the current session; edit pgmon.yaml or pgmon.yml if you want the new theme to persist across restarts. If a custom YAML theme uses the same name as a built-in theme, the custom definition overrides the built-in one.
CLI Options
-d, --dsn <STRING>: PostgreSQL connection string (optional ifPGMON_DSNor.pgpassis available)[ALIAS]: Optional connection alias frompgmon.yamlorpgmon.yml-c, --config <PATH>: Explicit path topgmon.yamlorpgmon.yml--connect-timeout-ms <u64>: Connection timeout in milliseconds (default: 3000)--query-output-dir <PATH>: Directory used when saving selected queries withEnter-r, --refresh-ms <u64>: Refresh interval (default: 1000)-n, --top-n <u32>: Rows to show (default: 10)--home-view <activity|statements>: Initial view-s, --sort <total_time|mean_time|calls>: Statements sort column (default:total_time)-v: Verbose logging
Connection precedence is: explicit --dsn, then positional alias from pgmon.yaml or pgmon.yml, then default_connection, then PGMON_DSN, then the first usable entry in PGPASSFILE or ~/.pgpass. If no aliases are configured at all, the resolution simply continues to PGMON_DSN and .pgpass.
TUI Shortcuts
1-8: switch tabsh/l: previous or next tabj/k: move selection up or down/: search or filter the current viewe: export the current table as CSV or JSON inActivityandStatementsm: cycle the Activity chart between Connections, TPS, DML/s, Temp Bytes/s, and Growth Bytes/sT: open the theme picker when built-in or custom themes are available?: open contextual in-app help for the current viewq: quit or close the current modal
Config Validation
Use pgmon check-config to validate configuration loading and the effective connection resolution without starting the TUI.
Examples:
The report includes:
- which config file was loaded, or whether built-in defaults are being used
- configured aliases, default connection, and active theme
- invalid color or alias/default-connection issues
- the effective connection source (
--dsn, alias,PGMON_DSN, or.pgpass) - a safe connection target summary without printing passwords
Connection & Capability Status
- The Activity summary now shows the current connection target, observed refresh latency, and last successful refresh state.
- The footer highlights offline/reconnect state when background refreshes fail and shows a slow-link indicator when refreshes exceed the configured interval.
Statements,IO, andReplicationnow show explicit capability panels whenpg_stat_statements,pg_stat_io, or replication settings are unavailable instead of rendering synthetic placeholder rows.- On slower or remote links,
pgmonreduces extra metadata round trips by caching capability checks and uses the observed refresh latency to avoid overly aggressive background polling.
Query Inspection
pgmon has two query-inspection flows:
- In
Statements, pression the selected row to open a detail modal with the database name, full SQL text, and aggregated timing counters frompg_stat_statements. - In
Activity, pression the selected session to inspect the current query text for that backend and optionally runEXPLAIN (ANALYZE, BUFFERS).
Inside the query detail modal:
Entersaves the SQL text to--query-output-diror the system temp directory.xrunsEXPLAIN (ANALYZE, BUFFERS)only for queries opened fromActivity.
Normalized Query Limitation
pg_stat_statements often stores normalized SQL such as:
SELECT * FROM accounts WHERE id = $1
Those placeholders do not include actual runtime values, so pgmon cannot safely execute EXPLAIN ANALYZE for them.
For that reason, Statements is now an inspect-only view for query text and aggregated timings. Its detail modal does not offer EXPLAIN ANALYZE, because the SQL usually represents a normalized statement shape rather than one executable statement with real values.
When a normalized query is opened from Activity:
- the modal shows a warning
- the
xaction is marked as unavailable - pressing
xkeeps the modal open and shows a notice instead of sending the query to PostgreSQL
If you need an execution plan for a normalized statement, copy the SQL and replace $1, $2, and similar placeholders with real literal values in a separate session before running EXPLAIN.
View Notes
- In the Database view, press
Enteron a selected database row to browse schemas and tables for that database, and pressEscto return to the summary view. - In the Activity view, use
a,w,b, andtto switch between active, waiting, blocking, and idle-in-transaction session subviews. - In the Activity view, press
mto cycle the chart between Connections, TPS, DML/s, Temp Bytes/s, and Growth Bytes/s without triggering a refresh. - Press
?in any main view to open contextual help with that view's shortcuts, important limitations, and brief metric explanations.