· 5 min read ·

TUI Clients for Postgres: What pgtui Gets Right About the Design Space

Source: lobsters

Most database clients live at one of two extremes. On one end, you have the official psql binary: a REPL that does the job and nothing more, no frills, no autocomplete unless you configure readline by hand. On the other end, you have full GUI applications like DBeaver, TablePlus, or pgAdmin, with connection managers and schema trees and result grids. The middle ground, terminal applications that are more than a REPL but don’t require a display server, is surprisingly thin.

pgtui, introduced on the author’s programming blog, is a new entrant into that middle ground. It’s a Terminal User Interface client for PostgreSQL, which puts it in a different category from tools like pgcli even though they’re both terminal-based and both written in Python.

The distinction matters. pgcli is fundamentally a REPL with excellent autocomplete, syntax highlighting, and \pset pager integration. It works the way you’d expect a terminal tool to work: you type a query, press enter, get output. The interactivity is limited to the input line. pgtui, by contrast, is built as a TUI, meaning it manages the entire terminal screen, divides it into panes, and responds to keyboard input that isn’t just query submission.

The REPL vs. TUI Distinction

This design difference has real implications for what the tool can do. A REPL client prints results and moves on; scrolling back through output means scrolling the terminal buffer, which gets messy fast with wide tables. A TUI client owns its layout, which means it can keep a result pane fixed, let you scroll within it using keyboard navigation, and maintain persistent context like a schema browser or query history without that context scrolling off screen.

Consider the workflow difference when you’re exploring an unfamiliar database. In psql or pgcli, you’ll run \dt to list tables, read the output, run \d tablename to inspect a schema, read that output, then write your query. Each step pushes the previous one up the terminal. In a TUI, a schema browser can sit in a sidebar the entire session, and you navigate it with the keyboard while writing queries in a separate pane.

This is what makes dedicated TUI clients interesting: they offer a workflow that’s structurally closer to a GUI without leaving the terminal. For developers who live in tmux and vim and want to keep their hands on the keyboard, that’s a real ergonomic improvement.

The Framework Question

Building a TUI in Python used to mean choosing between curses, which is powerful but tedious, or urwid, which has a steeper learning curve than its widget count suggests. The landscape changed significantly with Textual, the framework from Will McGugan and the team behind Rich. Textual brings a CSS-like layout system and reactive state management to Python terminal apps, which substantially reduces the boilerplate involved in building a multi-pane TUI.

pgcli itself is built on prompt_toolkit, which is well-suited for REPL-style interfaces with sophisticated input handling but isn’t designed for full-screen multi-pane layouts. If pgtui is targeting the full TUI design space, a framework like Textual is a more natural fit.

The Go ecosystem has Bubble Tea and Rust has Ratatui (formerly tui-rs), both of which follow the Elm architecture with immutable state and message passing. These tend to produce very responsive terminal apps but require more upfront thinking about state management. Python’s Textual sits in a more familiar object-oriented model that lowers the barrier for contributors.

Comparing the Existing Landscape

For Postgres specifically, the notable terminal clients are:

  • psql: ships with PostgreSQL, mature, feature-complete at the REPL level, but minimal ergonomics
  • pgcli: autocomplete, syntax highlighting, multi-line editing, smart pager integration; still fundamentally a REPL
  • usql: Go-based universal client supporting dozens of databases including PostgreSQL, useful for polyglot shops
  • lazysql: a Bubble Tea-based TUI that supports multiple databases with a more GUI-like layout

lazysql is probably the closest prior art to pgtui in terms of design philosophy: it’s a proper TUI with panes, keyboard navigation, and persistent layout. It models itself loosely on lazygit, which has become something of a canonical example of what a TUI developer tool can be. The challenge lazysql faces is being multi-database: supporting MySQL, PostgreSQL, SQLite, and others simultaneously means it can’t lean into PostgreSQL-specific features like EXPLAIN visualization, psql meta-commands, or extension-specific types.

A Postgres-specific TUI can afford to be opinionated. It can render EXPLAIN ANALYZE output as a tree rather than raw text. It can understand \copy, show table inheritance, surface partition hierarchies, and display type information with PostgreSQL’s type system in mind. That specialization is where a tool like pgtui has room to offer something pgcli and lazysql don’t.

What Makes a Good Database TUI

The features that tend to matter most in practice are consistent across tools. Result pane scrolling with both row and column navigation is table stakes; horizontal scrolling for wide tables is often worse in TUI clients than in simple pagers like pspg. Query history with search beats readline-style up-arrow navigation for anyone who writes more than a handful of queries per session. Schema browsing is most useful when it shows column types, indexes, and foreign keys in one place without switching context.

Less common but high-value features include inline query explain visualization, connection management with named profiles, and live result refresh for monitoring queries. The last one is particularly useful in operational contexts where you want to watch a SELECT count(*) FROM jobs WHERE status = 'pending' update as workers process items.

The harder design questions involve how to handle errors, transactions, and multi-statement scripts. A TUI that wraps every statement in an implicit transaction and rolls back on error behaves differently from one that sends statements directly. psql’s \set ON_ERROR_STOP behavior is the kind of thing that matters in scripts but is awkward to surface in a TUI context.

Why This Keeps Getting Built

pgtui joins a long line of attempts to find the right point in the design space between psql and a GUI client. The fact that people keep building these tools reflects a genuine unmet need: psql is too bare-bones for exploratory work, pgcli is excellent but still REPL-shaped, and GUI clients require leaving the terminal environment that many developers prefer for everything else.

The tools that succeed in this space tend to pick a specific workflow and optimize for it, rather than trying to replicate every GUI feature in a terminal. A focused Postgres TUI that does query editing, result browsing, and schema inspection well, and does them with keyboard-first navigation and zero mouse dependency, would be genuinely useful for a large segment of backend developers.

pgtui is new enough that the interesting question is which parts of that design space it decides to own. The introduction post is the starting point; where it goes from here depends on what friction points the author keeps hitting in their own Postgres workflow, which is usually the most reliable compass for a solo open-source project.

Was this interesting?