pgview
pgview is a lightweight, keyboard-driven PostgreSQL browser for the terminal. Built in Go using the same TUI framework as k9s, it lets you connect to any PostgreSQL-compatible endpoint — direct host, pgBouncer, RDS Proxy, or SSH tunnel — and navigate tables, inspect schemas, filter rows, edit data, and run arbitrary SQL queries, all without leaving your terminal.
Features
k9s-style TUI
Navigable table list, data view, schema browser, and SQL editor — same interaction model as the Kubernetes CLI.
Connect Anywhere
host:port, pgBouncer, RDS Proxy, SSH tunnel, or a full postgres:// DSN. PgBouncer simple-query protocol supported.
Smart Filter DSL
Press / to filter rows with col=val, col=%sub%, comparisons, or free text. Array and JSONB columns match element-wise.
SQL Editor
Full-screen editor with schema-aware Tab completion — type-matched operators, table names in FROM/JOIN, column names in SELECT/WHERE.
SQL Templates
Ctrl+T opens a side panel of pre-filled Query, Write, and DDL templates built from the current table's real column and PK names.
Row Viewer & Editor
Press f to open a full-screen two-column view of the selected row. Edit any field in-place and commit with Ctrl+S.
Mouse & Touchpad
Vertical scroll moves row selection. Horizontal two-finger swipe pans wide column sets. Works in all table views.
Query History
Ctrl+R in the SQL editor shows the last 50 queries, most-recent-first. Press Enter to reload any entry.
Fuzzy Table Search
Press / in the table list for a full-screen fuzzy finder across all schemas. Matched characters highlighted in blue; ranked by consecutive runs and word boundaries.
Export to CSV / JSON
Press E (Shift+E) in the data view to export the full result set (no page limit) to a file. Interactive format + path prompt; NULL → empty string in CSV, null in JSON.
Schema Browser
Press d from the table list or data view to open a 4-tab panel: Columns, Indexes, Constraints, and a reconstructed DDL view. Navigate with 1–4 or Tab.
Multi-Arch Releases
Pre-built binaries for linux/amd64, linux/arm64, darwin/amd64, and darwin/arm64 on every GitHub release.
Want to try it right now?
Follow the step-by-step guide to spin up a local Postgres instance with Docker, load seed data, download the binary, and walk through every feature — no existing database required.
Installation
Prerequisites
Go 1.22 or later — go.dev/dl
Download a binary
Pre-built binaries are available on the Releases page for linux and macOS (amd64 and arm64).
# macOS arm64 example
curl -L https://github.com/sibasismukherjee/pgview/releases/latest/download/pgview-darwin-arm64 \
-o /usr/local/bin/pgview
chmod +x /usr/local/bin/pgview
Build from source
git clone https://github.com/sibasismukherjee/pgview.git
cd pgview
make build # produces ./pgview
Install to PATH
make install # go install — places binary in $(go env GOPATH)/bin
Connecting
# Interactive prompts for all connection details
pgview
# Host and port with explicit credentials
pgview -url myproxy.internal:5432 -username myuser -dbname mydb
# Full DSN (password embedded in URL)
pgview -url "postgres://myuser:secret@localhost:5432/mydb?sslmode=disable"
# Disable SSL for local development
pgview -url localhost -username postgres -dbname mydb -sslmode disable
CLI Flags
| Flag | Description | Default |
|---|---|---|
-url | PostgreSQL connection URL — host, host:port, or postgres://… | prompted |
-username | Database username | prompted |
-password | Database password (prompted securely if omitted) | prompted |
-dbname | Database name | postgres |
-sslmode | disable | allow | prefer | require | prefer |
-version | Print version and exit | — |
Table List
The default view after connecting. Lists all tables and views in the database, grouped by schema.
pgview │ <↵> view <d> schema <i> stats │ Tables admin@mydb · local │ </> search <r> refresh <e> SQL <q> quit │ public ────────────────────────────────────────────────────────────────────────────────────── schema table type public orders BASE TABLE public products BASE TABLE ▶ public customers BASE TABLE reporting monthly_totals VIEW
| Key | Action |
|---|---|
| ↑ / ↓ | Move selection |
| Enter | Open data view for the selected table |
| d | Open schema browser (Columns, Indexes, Constraints, DDL) |
| i | Show table stats (estimated row count, PK, index count) |
| / | Fuzzy search across all schemas and tables |
| r | Refresh the list |
| e | Open SQL editor |
| q | Quit |
Fuzzy Table Search
Press / from the table list to open a full-screen fuzzy finder that searches across all schemas simultaneously. Results update as you type.
pgview │ <↵> open <Esc> cancel │ <↑↓> navigate │ type to filter all schemas admin@mydb · local │ ────────────────────────────────────────────────────────────────────────────────────── / ord ────────────────────────────────────────────────────────────────────────────────────── public.orders public.order_items reporting.daily_order_summary
| Key | Action |
|---|---|
| Type characters | Filter all schemas and tables by fuzzy match (subsequence) |
| ↑ / ↓ | Navigate results |
| Enter | Open selected table's data view |
| Esc | Close and return to table list |
Matched characters are highlighted in blue. Schema names shown in muted gray, table names in white. Results are ranked by match quality — consecutive character runs and word-boundary hits score higher than scattered matches.
Data View
Shows rows of the selected table, 200 per page. Type-aware cell colouring: numbers, booleans, UUIDs, timestamps, JSON, and NULL each have a distinct colour.
pgview │ <Esc> back <g> top <G> bottom │ <n>/<p> page │ </> filter │ Data public.customers
admin@mydb · local │ <d> schema <f> row view/edit <E> export <i> stats │ 42 rows ~1.2K est · PK: id
──────────────────────────────────────────────────────────────────────────────────────────────────────────────
id name status created_at tags
▶ 1 Alice Johnson active 2024-01-15 09:23:11 {platform,growth}
3 Carol White active 2024-03-19 11:02:44 {platform,api}
7 Eve Martinez active 2024-05-01 16:14:09 {growth}
WHERE "status"::text ILIKE 'active'
| Key | Action |
|---|---|
| ↑ / ↓ | Move row selection |
| n / p | Next / previous page (200 rows per page) |
| g / G | Jump to top / bottom of current page |
| / | Open filter prompt |
| f | Open row viewer / editor |
| d | Open schema browser for this table |
| E | Export full result set to CSV or JSON (interactive format + path prompt) |
| i | Refresh table stats |
| r | Re-run current query |
| e | Open SQL editor (pre-filled with last query) |
| Esc | Back to table list (clears filter) |
Filter DSL
Press / in the data view to open the filter prompt. Terms are whitespace-separated and AND-ed together.
| Input | Behaviour |
|---|---|
col=val | Exact match — ILIKE 'val' for scalars, 'val' = ANY(col) for arrays |
col=%val% | Substring match — element-wise for arrays and JSONB |
col!=val | Negation |
col>val / col>=val | Numeric or date comparison |
name="john doe" | Quote values that contain spaces |
freetext | Search across all columns with ILIKE '%freetext%' |
text[], int[], uuid[]) and JSONB columns
are detected automatically from PostgreSQL OIDs and matched element-wise rather than casting
the whole value to text.
# Show only active rows with a specific tag / status=active tags=platform # Date range on a timestamp column / created_at>=2024-01-01 created_at<2025-01-01 # Free-text search across all columns / johnson
Export to CSV / JSON
Press E (Shift+E) from the data view to start an interactive two-step export flow. Works for both table browse and SQL query results.
| Step | Prompt | Notes |
|---|---|---|
| 1 | export format: | Type csv or json, press Enter |
| 2 | export to: | Pre-filled with ~/export_<table>_<timestamp>.<ext>; edit path, press Enter |
LIMIT or
OFFSET so all rows are written to the file, not just the visible
page. Success or error is shown in the footer bar.
NULL values are written as an empty string in CSV and as null in JSON.
Row Viewer & Editor
Press f in the data view to open a full-screen two-column table showing every column of the selected row alongside its value.
Row Viewer <e>/<↵> edit <Ctrl+S> save <Esc> close · public.customers · row 1
─────────────────────┬──────────────────────────────────────────────────────────
Column │ Value
─────────────────────┼──────────────────────────────────────────────────────────
id │ 1
name │ Alice Johnson
▶ status │ active (edited)
created_at │ 2024-01-15 09:23:11
tags │ {platform,growth}
─────────────────────┴──────────────────────────────────────────────────────────
1 unsaved change(s) — Ctrl+S to save, Esc to discard
edit status ▏ inactive▌
| Key | Action |
|---|---|
| ↑ / ↓ | Navigate fields |
| e / Enter | Edit the selected field (input bar pre-filled with current value) |
| Ctrl+S | Save — runs UPDATE … SET … WHERE pk = … and refreshes the data view |
| Esc | Close and return to data view |
Modified fields are highlighted in teal with an (edited) marker.
The footer shows a count of unsaved changes.
Type NULL (any case) to set a field to SQL NULL.
WHERE clause always uses the original primary-key
value loaded from the database, so editing a PK column itself is safe — the correct
row is still targeted.
Schema Browser
Press d from the table list or data view to open a four-tab panel for the selected table. Navigate tabs with 1–4 or Tab / Shift+Tab.
pgview │ <1> Columns <2> Indexes <3> Constraints <4> DDL │ Schema public.customers admin@mydb · local │ <Tab> next tab │ <↵> view data <e> SQL <Esc> back <q> quit ───────────────────────────────────────────────────────────────────────────────────────── [1] Columns [2] Indexes [3] Constraints [4] DDL ────────────────────────────────────────────────────────── Column Type Nullable Default id bigint NOT NULL name character varying(120) NOT NULL ▶ status text NULL 'active' created_at timestamp with tz NOT NULL now() tags text[] NULL
The DDL tab (4) shows a reconstructed CREATE TABLE statement using accurate type names from pg_catalog.format_type, inline constraints, and standalone CREATE INDEX statements for non-primary indexes:
[1] Columns [2] Indexes [3] Constraints [4] DDL
──────────────────────────────────────────────────────────
CREATE TABLE "public"."customers" (
"id" bigint NOT NULL DEFAULT nextval('customers_id_seq'),
"name" character varying(120) NOT NULL,
"status" text DEFAULT 'active',
"created_at" timestamp with time zone NOT NULL DEFAULT now(),
"tags" text[],
CONSTRAINT "customers_pkey" PRIMARY KEY (id),
CONSTRAINT "customers_status_check" CHECK (status = ANY (ARRAY['active','inactive']))
);
CREATE INDEX idx_customers_status ON public.customers USING btree (status);
| Key | Action |
|---|---|
| 1 | Columns tab — name, type, nullability, default |
| 2 | Indexes tab — name, unique/primary flags, method, definition |
| 3 | Constraints tab — name, type (PK / FK / UNIQUE / CHECK), definition |
| 4 | DDL tab — reconstructed CREATE TABLE with constraints and indexes |
| Tab / Shift+Tab | Cycle forward / backward through tabs |
| Enter | View data rows for this table (Columns, Indexes, Constraints tabs) |
| e | Open SQL editor |
| Esc | Back to table list |
| q | Quit |
SQL Editor
Press e from any view to open a full-screen SQL editor. When opened from the data view it is pre-filled with the last executed query.
pgview │ <Ctrl+E> run <Tab> complete <Ctrl+L> clear <Esc> cancel │ SQL Editor admin@mydb · local │ <Ctrl+R> history <Ctrl+T> templates │ ────────────────────────────────────────────────────────────────────────────────────────── SELECT * FROM "public"."customers" WHERE status = 'active' LIMIT 100▌
Schema-aware Tab completion
Completion is clause-sensitive. Pressing Tab prioritises suggestions based on context:
- Type-matched operator when the previous token is a known column in WHERE/ON/HAVING —
LIKE/ILIKEfor text,>=/<=for timestamps,IS TRUE/IS FALSEfor booleans,= ANY(for arrays,->/->>for JSON - Table name in FROM/JOIN context
- Column name in SELECT/WHERE/ORDER BY context
- SQL keyword or table name as fallback
| Key | Action |
|---|---|
| Ctrl+E | Execute query; results replace the data view |
| Tab | Context-aware completion popup |
| Ctrl+T | Open templates panel |
| Ctrl+R | Open query history panel |
| Ctrl+L | Clear editor |
| Esc | Cancel and return to previous view |
Templates Panel
Ctrl+T opens a panel on the left side of the SQL editor. Templates are pre-filled with the current table's real column names, quoted identifiers, and primary-key column.
Templates │ ── Query ───────────── │ SELECT * SELECT * │ FROM "public"."customers" SELECT cols │ LIMIT 100▌ SELECT WHERE │ COUNT │ ── Write ───────────── │ INSERT │ UPDATE │ DELETE │ UPSERT │ ── DDL ─────────────── │ ADD COLUMN │ DROP COLUMN │ CREATE INDEX │ ANALYZE │ TRUNCATE │
| Category | Templates |
|---|---|
| Query | SELECT *, SELECT cols, SELECT WHERE, COUNT |
| Write | INSERT, UPDATE, DELETE, UPSERT (ON CONFLICT) |
| DDL | ADD COLUMN, DROP COLUMN, CREATE INDEX, ANALYZE, TRUNCATE |
Use ↑/↓ to navigate (category headers are skipped), Enter to load the template into the editor, Esc to return focus to the editor.
schema, table, and col1 placeholders are used.
Query History
Ctrl+R in the SQL editor opens a navigable history panel showing the last 50 queries, most-recent-first. Press Enter to load a query back into the editor, or Esc to close without loading.
Mouse & Touchpad
All table views (table list, data view, schema browser) support scroll gestures:
| Gesture | Action |
|---|---|
| Mouse wheel up / two-finger swipe up | Move row selection up |
| Mouse wheel down / two-finger swipe down | Move row selection down |
| Two-finger swipe left / WheelLeft | Pan columns left (wide result sets) |
| Two-finger swipe right / WheelRight | Pan columns right |
The SQL editor's text area handles its own scroll natively and is unaffected by the global capture.
Full Keyboard Reference
Table List
| Key | Action |
|---|---|
| ↑ / ↓ | Move selection |
| Enter | View data rows |
| d | Open schema browser |
| i | Table stats (estimated rows, PK, index count) |
| / | Fuzzy search across all schemas and tables |
| r | Refresh list |
| e | Open SQL editor |
| q | Quit |
Fuzzy Search
| Key | Action |
|---|---|
| Type characters | Filter all schemas and tables |
| ↑ / ↓ | Navigate results |
| Enter | Open selected table's data view |
| Esc | Close, return to table list |
Data View
| Key | Action |
|---|---|
| ↑ / ↓ | Move row selection |
| n / p | Next / previous page (200 rows) |
| g / G | Top / bottom of page |
| / | Filter prompt |
| f | Row viewer / editor |
| d | Open schema browser |
| E | Export to CSV or JSON |
| i | Table stats |
| r | Re-run query |
| e | SQL editor |
| Esc | Back to table list |
Row Viewer / Editor
| Key | Action |
|---|---|
| ↑ / ↓ | Navigate fields |
| e / Enter | Edit selected field |
| Ctrl+S | Save changes (UPDATE) |
| Esc | Close, return to data view |
Schema Browser
| Key | Action |
|---|---|
| 1 | Columns tab |
| 2 | Indexes tab |
| 3 | Constraints tab |
| 4 | DDL tab |
| Tab / Shift+Tab | Cycle forward / backward through tabs |
| Enter | View data rows |
| e | SQL editor |
| Esc | Back to table list |
| q | Quit |
SQL Editor
| Key | Action |
|---|---|
| Ctrl+E | Execute query |
| Tab | Schema-aware completion |
| Ctrl+T | Templates panel |
| Ctrl+R | Query history |
| Ctrl+L | Clear editor |
| Esc | Cancel, go back |
Makefile Targets
| Target | Action |
|---|---|
make build | Compile binary to ./pgview |
make install | Install to $(go env GOPATH)/bin |
make run | Build and launch interactively |
make test | Run all unit tests with -race |
make lint | Run golangci-lint |
make tidy | go mod tidy |
make clean | Remove build artefacts |
Contributing
Contributions are welcome. The short version:
- Search or open an Issue first
- Fork → branch from
main→ PR - Tests and lint must pass — CI runs automatically on every PR
See CONTRIBUTING.md for the full guide, CODE_OF_CONDUCT.md for community standards, and SECURITY.md for reporting vulnerabilities privately.
License
pgview is released under the MIT License. Use it freely in personal and commercial projects.