| Crates.io | bestool-psql |
| lib.rs | bestool-psql |
| version | 1.4.0 |
| created_at | 2025-10-20 22:46:37.831785+00 |
| updated_at | 2026-01-07 10:11:50.396683+00 |
| description | psql-inspired client for PostgreSQL |
| homepage | |
| repository | https://github.com/beyondessential/bestool/tree/main/crates/psql |
| max_upload_size | |
| id | 1892849 |
| size | 881,276 |
This tool was initially created by BES as a series of augments on top of the native psql client to increase our safety when interacting with PostgreSQL databases, especially in sensitive environments. It has since been rewritten entirely as a standalone tool, which maintains a similar syntax as native psql, but with a different feature set and in some cases a different syntax and behaviour.
The primary features are
Available on crates.io:
cargo install bestool-psql
There are no binary builds available at this time.
The crate also exposes a library interface which embeds the tool in another CLI application.
| Argument | Short | Type | Default | Description |
|---|---|---|---|---|
CONNSTRING |
STRING |
required | Database name or connection string (e.g., 'mydb' or 'postgresql://user:password@localhost:5432/dbname') | |
--write |
-W |
FLAG |
false | Enable write mode for this session. By default the session is read-only. To enable writes, pass this flag. This also disables autocommit, so you need to issue a COMMIT; command whenever you perform a write (insert, update, etc), as an extra safety measure. |
--theme |
STRING |
auto | The theme of your terminal (light, dark, or auto). 'auto' attempts to detect terminal background, defaults to 'dark' if detection fails. | |
--audit-path |
PATH |
~/.local/state/bestool-psql/history.redb | Path to audit database |
All commands and some of the SQL has extensive tab completion, give it a try!
| Command | Description |
|---|---|
\help or \? |
Show a help page |
\q or Ctrl-D |
Quit |
\x |
Toggle expanded output mode |
\W |
Toggle write mode |
\R |
Toggle redaction mode |
\e [query] |
Edit query in external editor |
\i <file> [var=val...] |
Execute commands from file |
\o [file] |
Send query results to file (or close if no file) |
\re list[+] [N] |
List the last N (default 20) saved results |
\re show [n=N] [format=FMT] [to=PATH] [cols=COLS] [limit=N] [offset=N] |
Display a saved result |
\snip run <name> [var=val...] |
Run a saved snippet |
\snip save <name> |
Save the preceding command as a snippet |
\snip list |
Show the list of available snippets |
\snip edit <name> |
Load the snippet into the edit buffer without running it |
\set <name> <value> |
Set a variable |
\default <name> <value> |
Set a variable if not already set |
\unset <name> |
Unset a variable |
\get <name> |
Print a variable value |
\vars [pattern] |
List variables (optionally matching pattern) |
| Command | Alias | Description |
|---|---|---|
\describe [pattern] |
\d |
Describe database objects |
\list table [pattern] |
\dt |
List tables |
\list view [pattern] |
\dv |
List views |
\list function [pattern] |
\df |
List functions |
\list index [pattern] |
\di |
List indexes |
\list schema [pattern] |
\dn |
List schemas |
\list sequence [pattern] |
\ds |
List sequences |
There's also two modifiers you can add:
+ toggles "detailed" mode, which shows more information! toggles "same connection" mode; by default these commands are executed
in a separate connection so they can be used to explore the database without
affecting the current session. In some cases, you might want to execute them
in the same connection as the session, so that you can see changes you've
made to the database before committing them.Look in EXAMPLES.md for more.
Query modifiers are used after a query to modify its execution behaviour.
| Modifier | Description |
|---|---|
\g |
Execute query |
\gx |
Execute query with expanded output |
\gj |
Execute query with JSON output |
\gv |
Execute query without variable interpolation ("verbatim") |
\go <file> |
Execute query and write output to file |
\gset [prefix] |
Execute query and store results in variables |
Modifiers can be combined, e.g. \gxj for expanded JSON output.
Variables can be used within SQL queries to dynamically substitute values. Note this is a different syntax from native psql.
| Syntax | Description |
|---|---|
${name} |
Replace with variable value (errors if not set) |
${{name}} |
Escape: produces ${name} without replacement |
| Format | Use with | Description |
|---|---|---|
| Table | query \g or \re show format=table |
Default table format |
| Expanded | query \gx or \re show format=expanded |
One table per result row |
| JSON | query \gj or \re show format=json |
JSON lines: one row (as object) per line |
| Expanded JSON | query \gxj or \re show format=json-pretty |
An array of objects (one per row), pretty-printed |
| CSV | \re show format=csv |
Comma-separated values |
| Excel | \re show format=excel to=<filename> |
XLSX-format spreadsheet |
| SQLite | \re show format=sqlite to=<filename> |
SQLite database with a table named results |
# Connect to local database
bestool-psql mydb
# Connect with full connection string
bestool-psql "postgresql://user:password@localhost:5432/mydb"
# Enable write mode (remember to COMMIT!)
bestool-psql -W mydb
-- Set a variable
\set table_name users
-- Set a variable with a default value (only if not already set)
\default schema_name public
-- Use in query
SELECT * FROM ${table_name};
-- Get a variable value
\get table_name
-- Escape variable syntax
SELECT '${{table_name}}' as literal_text;
-- Unset a variable
\unset table_name
-- List all variables
\vars
-- Save current query as a snippet
\snip save my_query
-- Run the saved snippet later
\snip run my_query
-- Run snippet with variable override
\snip run my_query table_name=products
-- Expanded output
SELECT * FROM users \gx;
-- JSON output
SELECT * FROM users \gj;
-- Pretty-printed JSON
SELECT * FROM users \gxj;
-- Write to file
SELECT * FROM users \go /tmp/results.txt;
-- Execute commands from a file
\i /path/to/script.sql
-- With variables (that only apply to this file execution)
\i /path/to/script.sql var1=value1 var2=value2
\o /tmp/output.txt
-- This will print to the file instead of the screen
SELECT * FROM users;
-- This will print in json format to the file
SELECT * FROM users \gj;
-- Toggle off (now things will print to the screen again)
\o
Make sure to check out the EXAMPLES.md for more.