A PostgreSQL monitoring TUI inspired by pg_activity.
- 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.
cargo build --releasepgmon --dsn "postgresql://user:password@localhost:5432/postgres"
# Connect using an alias from pgmon.yaml or pgmon.yml
pgmon prod
# Load a specific config file
pgmon --config ./pgmon.yaml prod
# Use the config's default connection
pgmon --config ./pgmon.yaml
# Validate config loading and connection resolution without starting the TUI
pgmon check-config --config ./pgmon.yaml prod
# Specific home view and sort
pgmon --dsn "..." --home-view statements --sort total_time --top-n 20 --refresh-ms 2000
# Fail faster on unreachable hosts
pgmon --connect-timeout-ms 1500
# Save selected queries into a persistent directory
pgmon --query-output-dir "$HOME/.local/share/pgmon/queries"
# Or rely on PGMON_DSN / ~/.pgpass
PGMON_DSN="postgresql://postgres@localhost/postgres" pgmonpgmon 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.
# 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' columnBuilt-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.
-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.
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
Use pgmon check-config to validate configuration loading and the effective connection resolution without starting the TUI.
Examples:
pgmon check-config
pgmon check-config prod
pgmon check-config --config ./pgmon.yaml prod
pgmon check-config --dsn "postgresql://postgres@localhost/postgres"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
- 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.
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.
pg_stat_statements often stores normalized SQL such as:
SELECT * FROM accounts WHERE id = $1Those 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.
- 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.