pgview try it

Try pgview

v0.4.1 ~15 min setup no cloud account needed

This guide walks you through spinning up a local PostgreSQL instance with realistic seed data and exploring every feature of pgview hands-on. You will need a container runtime and the pgview binary — nothing else.

Total setup time is roughly 10–15 minutes. All resources run locally; nothing is sent to an external service.

Already have PostgreSQL running? Jump straight to Seed the Database to create the demo schema, then Get pgview.

Prerequisites

1 — Container runtime

You need one of the following to run PostgreSQL locally. Install the one that fits your OS:

Docker Desktop
Colima (macOS)
Podman
# macOS — install via Homebrew
brew install --cask docker

# Linux — follow the official script
curl -fsSL https://get.docker.com | sh
sudo usermod -aG docker $USER   # log out and back in after this

# Verify
docker --version

Then open the Docker Desktop application once so the daemon starts.

# Colima is a lightweight Docker runtime for macOS — no GUI required
brew install colima docker

# Start the VM (arm64 for Apple Silicon, x86_64 for Intel)
colima start

# Verify
docker --version

Colima starts a lightweight Lima VM and exposes the Docker socket. It uses fewer resources than Docker Desktop and has no paid tier.

# macOS
brew install podman
podman machine init
podman machine start

# Linux
sudo apt-get install -y podman   # Debian/Ubuntu
sudo dnf install -y podman       # Fedora/RHEL

# Alias docker → podman if you prefer
alias docker=podman

# Verify
podman --version

Podman is daemonless and runs containers rootless by default. All docker commands in this guide work identically with podman.

2 — Docker Hub account (free)

The PostgreSQL image is pulled from Docker Hub. Anonymous pulls are rate-limited, so a free account is recommended.

# Log in once — credentials are cached on disk
docker login

Create a free account at hub.docker.com if you do not have one yet.

3 — pgview binary

Covered in the Get pgview section below — no installation needed, it is a single static binary.

Start PostgreSQL

Run a PostgreSQL 16 container with a known user, password, and database name.

docker run -d \
  --name pgview-demo \
  -e POSTGRES_USER=demo \
  -e POSTGRES_PASSWORD=demo1234 \
  -e POSTGRES_DB=demodb \
  -p 5432:5432 \
  postgres:16-alpine
Apple Silicon (M1/M2/M3)? The postgres:16-alpine image ships multi-arch manifests — the right image is pulled automatically. No flags needed.

Wait a few seconds for the container to become healthy, then verify:

docker exec pgview-demo pg_isready -U demo -d demodb
# Expected: localhost:5432 - accepting connections
Port already in use? If port 5432 is taken by a local Postgres installation, map to a different host port: -p 5433:5432. Then pass pgview -url localhost:5433 later.

When you are done testing, stop and remove the container:

docker stop pgview-demo && docker rm pgview-demo

Seed the Database

Connect to the container and create a realistic demo schema with four related tables and several hundred rows.

docker exec -i pgview-demo psql -U demo -d demodb <<'SQL'

-- ─────────────────────────────────────────────────────────────
-- Schema: demo
-- ─────────────────────────────────────────────────────────────

CREATE SCHEMA IF NOT EXISTS demo;

-- customers
CREATE TABLE demo.customers (
  id          bigserial    PRIMARY KEY,
  name        text         NOT NULL,
  email       text         NOT NULL UNIQUE,
  status      text         NOT NULL DEFAULT 'active',
  created_at  timestamptz  NOT NULL DEFAULT now(),
  tags        text[]
);
COMMENT ON COLUMN demo.customers.tags IS 'freeform labels for segmentation';
CREATE INDEX idx_customers_status ON demo.customers (status);
ALTER TABLE demo.customers
  ADD CONSTRAINT customers_status_chk
  CHECK (status IN ('active', 'inactive', 'suspended'));

-- products
CREATE TABLE demo.products (
  id          serial       PRIMARY KEY,
  name        text         NOT NULL,
  category    text         NOT NULL,
  price       numeric(10,2)NOT NULL,
  stock_qty   int          NOT NULL DEFAULT 0
);
CREATE INDEX idx_products_category ON demo.products (category);

-- orders
CREATE TABLE demo.orders (
  id           bigserial    PRIMARY KEY,
  customer_id  bigint       NOT NULL REFERENCES demo.customers(id),
  total        numeric(10,2)NOT NULL,
  status       text         NOT NULL DEFAULT 'pending',
  created_at   timestamptz  NOT NULL DEFAULT now(),
  notes        jsonb
);
CREATE INDEX idx_orders_customer ON demo.orders (customer_id);
CREATE INDEX idx_orders_status  ON demo.orders (status);
ALTER TABLE demo.orders
  ADD CONSTRAINT orders_status_chk
  CHECK (status IN ('pending', 'paid', 'shipped', 'cancelled'));

-- order_items
CREATE TABLE demo.order_items (
  id          bigserial    PRIMARY KEY,
  order_id    bigint       NOT NULL REFERENCES demo.orders(id),
  product_id  int          NOT NULL REFERENCES demo.products(id),
  quantity    int          NOT NULL DEFAULT 1,
  unit_price  numeric(10,2)NOT NULL
);

-- ─────────────────────────────────────────────────────────────
-- Seed data
-- ─────────────────────────────────────────────────────────────

INSERT INTO demo.customers (name, email, status, tags) VALUES
  ('Alice Nguyen',   'alice@example.com',   'active',    '{vip,newsletter}'),
  ('Bob Okonkwo',    'bob@example.com',     'active',    '{newsletter}'),
  ('Carol Singh',    'carol@example.com',   'active',    '{vip}'),
  ('David Rossi',    'david@example.com',   'inactive',  NULL),
  ('Eve Martínez',   'eve@example.com',     'active',    '{vip,newsletter}'),
  ('Frank Dubois',   'frank@example.com',   'suspended', NULL),
  ('Grace Kim',      'grace@example.com',   'active',    '{newsletter}'),
  ('Hiro Tanaka',    'hiro@example.com',    'active',    '{vip}'),
  ('Ingrid Svensson','ingrid@example.com',  'active',    '{newsletter}'),
  ('James O''Brien', 'james@example.com',   'inactive',  NULL);

INSERT INTO demo.products (name, category, price, stock_qty) VALUES
  ('Wireless Keyboard',    'Electronics', 79.99,  50),
  ('USB-C Hub',            'Electronics', 49.99,  120),
  ('Mechanical Keyboard',  'Electronics', 149.00, 30),
  ('Desk Lamp',            'Office',      35.50,  200),
  ('Notebook A5',          'Stationery',  8.99,   500),
  ('Ergonomic Mouse',      'Electronics', 59.00,  75),
  ('Monitor Stand',        'Office',      89.00,  40),
  ('Cable Organiser',      'Office',      14.99,  300);

INSERT INTO demo.orders (customer_id, total, status, notes) VALUES
  (1, 129.98, 'paid',      '{"source":"web","promo":"SUMMER10"}'),
  (2, 49.99,  'shipped',   NULL),
  (3, 238.00, 'paid',      '{"source":"app"}'),
  (1, 35.50,  'pending',   NULL),
  (5, 59.00,  'paid',      '{"source":"web"}'),
  (7, 8.99,   'cancelled', NULL),
  (8, 168.99, 'shipped',   '{"source":"app","gift":true}'),
  (9, 14.99,  'paid',      NULL);

INSERT INTO demo.order_items (order_id, product_id, quantity, unit_price) VALUES
  (1, 1, 1, 79.99), (1, 2, 1, 49.99),
  (2, 2, 1, 49.99),
  (3, 3, 1, 149.00), (3, 7, 1, 89.00),
  (4, 4, 1, 35.50),
  (5, 6, 1, 59.00),
  (6, 5, 1, 8.99),
  (7, 3, 1, 149.00), (7, 6, 1, 19.99),
  (8, 8, 1, 14.99);

ANALYZE;
SQL

Verify the seed data was inserted:

docker exec pgview-demo psql -U demo -d demodb \
  -c "SELECT schemaname, tablename, n_live_tup FROM pg_stat_user_tables WHERE schemaname = 'demo' ORDER BY tablename;"

You should see four rows with non-zero n_live_tup values.

Get pgview

pgview is a single static binary — no runtime dependencies, no installer. Download the build that matches your OS and chip from the v0.4.1 release page.

PlatformBinary to download
macOS — Apple Silicon (M1/M2/M3/M4)pgview-darwin-arm64
macOS — Intelpgview-darwin-amd64
Linux — x86-64pgview-linux-amd64
macOS arm64
macOS Intel
Linux
# Download
curl -L https://github.com/sibasismukherjee/pgview/releases/download/v0.4.1/pgview-darwin-arm64 \
  -o pgview

# Make executable
chmod +x pgview

# Optional: move to PATH so you can run it from anywhere
mv pgview /usr/local/bin/pgview

# Verify
pgview -version
macOS Gatekeeper warning? Because the binary is not signed with an Apple Developer certificate, macOS may block it on first launch. Run: xattr -d com.apple.quarantine pgview then try again. Alternatively: System Settings → Privacy & Security → click "Allow Anyway".
# Download
curl -L https://github.com/sibasismukherjee/pgview/releases/download/v0.4.1/pgview-darwin-amd64 \
  -o pgview

chmod +x pgview
mv pgview /usr/local/bin/pgview
pgview -version
Same Gatekeeper note as arm64 above: xattr -d com.apple.quarantine pgview if blocked.
# Download
curl -L https://github.com/sibasismukherjee/pgview/releases/download/v0.4.1/pgview-linux-amd64 \
  -o pgview

chmod +x pgview
sudo mv pgview /usr/local/bin/pgview
pgview -version

Or build from source if you have Go 1.22+:

git clone https://github.com/sibasismukherjee/pgview.git
cd pgview
make build    # produces ./pgview

Connect to PostgreSQL

Run pgview and point it at the container you started earlier:

# One-liner with all flags
pgview -url localhost:5432 -username demo -password demo1234 -dbname demodb -sslmode disable

Or run interactively and enter each value at the prompt:

pgview
# Connection URL (host:port): localhost:5432
# Username: demo
# Database [postgres]: demodb
# Password: demo1234  ← not echoed

pgview opens directly on the Table List. You should see the four tables in the demo schema: customers, order_items, orders, and products.

The top-left corner always shows demo@demodb · localhost — a quick reminder of which database you are connected to.

Feature 1 — Table List

The table list is the home screen. Use / to move the selection. Try these keys:

i — Table stats. Hover over demo.orders and press i. The top-right panel shows the estimated row count, primary key column(s), and index count — fetched from pg_class without scanning the table.
Enter — Open data view. Press Enter on any table to browse its rows. Press Esc to return here.
d — Schema browser. Press d on demo.orders to open the 4-tab schema panel. Covered in detail in the Schema Browser section.
e — SQL editor. Opens a full-screen SQL editor pre-filled with nothing (from the table list) or with the last query (from the data view).
q — Quit. Exits pgview cleanly.

Feature 2 — Fuzzy Table Search

From the table list, press / to open the full-screen fuzzy finder. It searches all schemas simultaneously.

Type ord — pgview instantly filters to demo.orders and demo.order_items. Matched characters are highlighted in blue.
Type cu — narrows to demo.customers. Press Enter to jump straight into its data view.
Press Esc to return to the table list with no change.
Fuzzy scoring rewards consecutive matches and word-boundary hits — so oi ranks order_items above orders.

Feature 3 — Data View & Filter DSL

Navigate to demo.orders (fuzzy search ord then Enter). The data view shows 200 rows per page with type-aware colouring: numeric values are green, timestamps orange, NULL is dim gray, booleans are teal/red.

/ — Filter prompt. Try these filters one at a time. Press Esc between each to clear:
status=paid               # exact match
status!=cancelled         # negation
total>100                 # numeric comparison
total>=50 status=shipped  # AND — two terms
Array filter on customers. Navigate to demo.customers and try:
tags=vip          # element-wise: ANY(tags) = 'vip'
tags=%newsletter% # substring per element
JSONB filter on orders. Navigate back to demo.orders and try:
notes=%web%      # matches rows where notes contains "web"
g / G — Jump to the top or bottom of the result set. n / p — Next / previous page (200 rows per page).
Scroll left / right. On a wide result set (try demo.order_items), swipe horizontally with two fingers or use WheelLeft / WheelRight to pan columns.

Feature 4 — Schema Browser

From the table list or data view, press d to open the 4-tab schema panel. Try it on demo.orders, which has a FK, a CHECK constraint, two indexes, and a rich DDL.

1 — Columns tab. Shows column name, type (accurate via pg_catalog.format_type), nullability, and default. Notice total is numeric(10,2) and notes is jsonb.
2 — Indexes tab. You'll see orders_pkey (PRIMARY, btree), idx_orders_customer, and idx_orders_status with their full pg_get_indexdef definitions.
3 — Constraints tab. Shows orders_pkey (PRIMARY KEY), the FK to customers, and the orders_status_chk CHECK constraint with its expression.
4 — DDL tab. A reconstructed CREATE TABLE statement — copy-pasteable into psql or a migration file. Scroll down to see the standalone CREATE INDEX lines.
Tab / Shift+Tab — cycle through tabs without using the number keys. Esc returns to the table list.

Feature 5 — Row Viewer & Inline Editor

Navigate into demo.customers, select any row, and press f.

Row Viewer — every column with its current value in a two-column bordered table. Type-aware colouring matches the data view (array values, NULL, etc.).
Press e or Enter on the status field. The input bar at the bottom pre-fills with the current value (active). Change it to inactive and press Enter. The field is now highlighted in teal with an (edited) marker.
Press Ctrl+S to commit. pgview runs:
UPDATE demo.customers SET status = 'inactive' WHERE id = <original_id>
The data view refreshes and the change is visible immediately.
Type NULL in the input bar to set a field to SQL NULL (any case works). Useful for clearing the tags array.
Press Esc to close without saving.
Editing the primary-key column is safe — pgview captures the original PK value at open time and uses it in the WHERE clause, so the right row is always targeted.

Feature 6 — SQL Editor & Templates

Press e from any view to open the full-screen SQL editor. From the data view the editor is pre-filled with the last query.

Write and run a query. Type:
SELECT c.name, COUNT(o.id) AS order_count, SUM(o.total) AS total_spent
FROM demo.customers c
LEFT JOIN demo.orders o ON o.customer_id = c.id
GROUP BY c.name
ORDER BY total_spent DESC NULLS LAST;
Press Ctrl+E to run. Results appear in the data view.
Tab — schema-aware completion. Type SELECT * FROM demo. and press Tab. pgview suggests table names. After selecting one, type a column name prefix and press Tab again for column suggestions in context.
Ctrl+T — templates panel. Open the editor from demo.orders data view, then press Ctrl+T. The left panel fills with pre-built queries using the real column names of orders. Select INSERT and press Enter — a complete INSERT template with all columns drops into the editor.
Ctrl+R — query history. Shows the last 50 queries most-recent-first. Press Enter to reload any entry. Esc closes the panel.
Ctrl+L — clear the editor. Esc — cancel and return to the previous view.

Feature 7 — Export to CSV / JSON

From any data view (table browse or SQL results), press E (Shift+E) to start the interactive export flow.

Step 1: choose format. At the export format: prompt type csv and press Enter.
Step 2: confirm path. The path is pre-filled as ~/export_orders_<timestamp>.csv. Press Enter to accept, or edit it first.
All rows are exported — not just the visible page. pgview re-runs the current query without LIMIT / OFFSET. With the status=paid filter active, only paid orders are written.
Open the file to verify:
head -5 ~/export_orders_*.csv
You'll see the header row followed by data rows; NULL fields are empty strings.
Try again with json format. NULL becomes null in the JSON output.

Feedback & Roadmap

Thank you for trying pgview! Your feedback shapes what gets built next.

Report an Issue

Found a bug, unexpected behaviour, or something that felt off? Open an issue on GitHub — include your OS, the binary you used, and steps to reproduce.

Open an Issue →

See the Roadmap

Curious what's coming next? The project board tracks every planned enhancement — EXPLAIN panel, clipboard copy, connection manager, inline cell editing, and more.

View Roadmap →

Feature requests are also welcome as GitHub Issues — browse the open issues first to see if your idea already has a thread, or open a new one with the enhancement label.

Clean up

When you are done, remove the demo container:

docker stop pgview-demo && docker rm pgview-demo