s9l

module
v0.13.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 7, 2026 License: MIT

README

s9l

A fast terminal database client. Connect to a database and run queries with one short command — simple to use, scriptable, and easy to extend to new databases.

Status: early development (v0.x). SQLite, PostgreSQL, MySQL, SQL Server and ClickHouse are supported today; more databases are on the roadmap. See docs/PLAN.md.

Features

  • Three ways to use it — one-shot s9l <conn> -e "SQL" for scripts, a REPL with s9l <conn>, or a full-screen lazygit-style TUI with s9l tui (see below).
  • Named connections — store connections in ~/.config/s9l/config.yaml and connect with s9l mydb. Passwords never live in the config (see below).
  • Multiple output formats--format table|json|csv|tsv. Defaults to a table on a terminal and TSV when piped, so output stays parseable.
  • Metadata commands\l (databases), \dt (tables), \d <table> (columns), \? (help).
  • Query history & saved queries — every query is recorded; favorite the ones you reuse.
  • Single static binary — pure-Go drivers, no CGO.

Install

# Homebrew (macOS / Linux)
brew install YangXplorer/tap/s9l

# Go
go install github.com/YangXplorer/s9l/cmd/s9l@latest

Or download a prebuilt binary from the releases page.

Quick start

# Run a one-off query against a SQLite file
s9l ./app.db -e "select * from users limit 5"

# Pipe-friendly output (TSV when not a TTY); JSON on demand
s9l ./app.db -e "select * from users" --format json | jq '.[0]'

# Add a named connection, then use it
s9l conn add --id pg --driver postgres --host localhost --port 5432 \
    --user dev --database app --ssl --password-ref env:PGPASSWORD
s9l pg -e "select version()"

# Interactive REPL
s9l pg
s9l> \dt
s9l> select * from orders order by created_at desc limit 10;
s9l> \q

Configuration

Connections live in $XDG_CONFIG_HOME/s9l/config.yaml (falling back to ~/.config/s9l/config.yaml), written with 0600 permissions:

connections:
  - id: local
    driver: sqlite
    database: ./app.db
  - id: pg
    name: Dev Postgres
    driver: postgres
    host: localhost
    port: 5432
    user: dev
    database: app
    ssl: true
    password_ref: env:PGPASSWORD

Passwords are never stored in the config. password_ref points at the secret instead:

  • env:NAME — read from environment variable NAME (e.g. env:PGPASSWORD).
  • keychain://s9l/<key> — read from the OS keychain (macOS Keychain, Windows Credential Manager, Linux Secret Service).

Store a password in the keychain when adding a connection — password_ref is set for you, and the plaintext never touches config.yaml:

s9l conn add --id pg --driver postgres --host localhost --user dev \
    --database app --password 'your-password'

(Passing --password on the command line can leak into shell history; for CI or scripts prefer --password-ref env:PGPASSWORD.)

Manage connections with s9l conn add|list|rm.

TLS: beyond --ssl, use --ssl-mode for finer control (postgres require|verify-ca|verify-full, mysql skip-verify|preferred, sqlserver require|verify-full) and --tls-ca / --tls-cert / --tls-key for a CA and client certificate (CA: postgres & SQL Server; client cert: postgres). ssl: true keeps its previous behavior.

SSH tunnel: reach a database behind a bastion with --ssh-host (plus --ssh-port/--ssh-user/--ssh-key). The bastion host key is verified against ~/.ssh/known_hosts (override with --ssh-known-hosts, or skip with the insecure --ssh-insecure-host-key); without --ssh-key the SSH agent is used.

Commands

Command Description
s9l <conn|dsn> -e "SQL" Run a query and exit
s9l <conn|dsn> Start the interactive REPL
s9l conn add|list|rm Manage named connections
s9l history [--limit N] Show recent query history
s9l history stats [--top N] Aggregate stats (counts, success rate, avg time, top queries)
s9l saved add|list|search|rm|run Manage and run saved queries
s9l saved folder add|rm · folders · mv Organize saved queries into folders
s9l import <conn|dsn> --table T --file f Bulk-load a CSV/JSON file into a table
s9l tui [connection] Launch the full-screen TUI
s9l --version Print version

In the REPL / with -e: \l, \dt, \d [table], \?, and \q (REPL quit). Press Tab in the REPL to complete keywords, table names, and column names (including table.column and columns of tables named in the current line). For named connections the schema is cached at $XDG_CACHE_HOME/s9l/schema.db (falling back to ~/.cache/s9l/schema.db), so completion stays available across sessions and even when a live metadata lookup fails.

Flags: --format table|json|csv|tsv, --max-col-width N (truncate table cells), --timeout 30s (abort a slow query). Press Ctrl-C to cancel a running query.

On a terminal, large output is paged through $PAGER (default less -FIRX, so results that fit one screen print inline). Set $PAGER/$S9L_PAGER to choose a pager, or pass --no-pager (or S9L_PAGER=) to disable. Piped/non-TTY output is never paged, so scripts are unaffected.

Terminal UI

A full-screen, lazygit-style interface — connections, schema tree, results and a SQL editor, all keyboard-driven:

s9l tui          # choose a connection inside the UI
s9l tui mydb     # auto-connect to a named connection

Panels: Connections (a tree of your configured connections) · Schema · Results · SQL editor. On MySQL, pressing Enter on a connection connects and expands it to its databases; pick a database and the Schema panel lists that database's tables (handy when the connection has no default database). Other engines list the connected database's tables directly. Press / in the Schema panel to filter table names. Select a table to preview it, or write SQL and run it with F5. Queries run asynchronously and can be cancelled with Esc.

Key Action
Tab / Shift-Tab switch panel
1 / 2 / 3 / 4 Connections / Schema / Results / SQL editor
Up/Down · j/k navigate within a panel
Enter Connections: connect + list databases · pick a database · Schema: preview table
n / e / d add / edit / delete a connection (Connections panel; passwords in the keychain)
F5 run the SQL editor
/ filter — Schema: table names · Results: rows (substring, case-insensitive)
Esc cancel a running query · clear the filter
Ctrl-R query history — Enter loads an entry into the editor
Ctrl-F saved queries — Enter runs the selected one
Ctrl-S save the editor's SQL as a favorite
Ctrl-E export the current results to a file (csv/json/tsv by extension)
? help overlay
q / Ctrl-C quit

The TUI uses a lazygit-style theme (numbered, rounded panels; the focused panel is highlighted; a shortcut bar sits at the bottom) and inherits your terminal's background so it blends in like lazygit. Set NO_COLOR to disable colors. The Connections panel shows a per-database icon next to each name; icons default to short ASCII tags ([pg], [my], [sq], [ms]) — set S9L_TUI_ICONS=nerd for Nerd Font glyphs, or S9L_TUI_ICONS=off to hide them.

Development

go build ./...
go test -short ./...   # unit + in-memory SQLite (no Docker)
go test ./...          # also runs container-based PostgreSQL tests (needs Docker)
golangci-lint run

For a full walkthrough of every command, output format, and the TUI, see the user manual (docs/MANUAL.md).

See docs/ for the plan (PLAN.md), task breakdown (TASKS.md), testing strategy (TESTING.md), and release/CI design (RELEASE.md).

License

MIT — see LICENSE.

Directories

Path Synopsis
cmd
s9l command
Command s9l is a fast terminal database client.
Command s9l is a fast terminal database client.
internal
cli
Package cli will hold command/flag parsing as the surface grows beyond the Phase 0 single-shot entrypoint in cmd/s9l.
Package cli will hold command/flag parsing as the surface grows beyond the Phase 0 single-shot entrypoint in cmd/s9l.
config
Package config loads and persists s9l's YAML connection configuration from $XDG_CONFIG_HOME/s9l/config.yaml (falling back to ~/.config/s9l/config.yaml).
Package config loads and persists s9l's YAML connection configuration from $XDG_CONFIG_HOME/s9l/config.yaml (falling back to ~/.config/s9l/config.yaml).
dial
Package dial opens a database connection for a configured connection, transparently setting up an SSH tunnel first when the connection requests one.
Package dial opens a database connection for a configured connection, transparently setting up an SSH tunnel first when the connection requests one.
driver
Package driver defines the database driver abstraction for s9l.
Package driver defines the database driver abstraction for s9l.
driver/clickhouse
Package clickhouse implements the s9l driver for ClickHouse using the pure-Go ClickHouse/clickhouse-go/v2 adapter (database/sql, no CGO).
Package clickhouse implements the s9l driver for ClickHouse using the pure-Go ClickHouse/clickhouse-go/v2 adapter (database/sql, no CGO).
driver/drivertest
Package drivertest provides a conformance suite that every driver.Driver implementation must pass.
Package drivertest provides a conformance suite that every driver.Driver implementation must pass.
driver/mysql
Package mysql implements the s9l driver for MySQL using the pure-Go go-sql-driver/mysql adapter (database/sql, no CGO).
Package mysql implements the s9l driver for MySQL using the pure-Go go-sql-driver/mysql adapter (database/sql, no CGO).
driver/postgres
Package postgres implements the s9l driver for PostgreSQL using the pure-Go jackc/pgx stdlib adapter (database/sql, no CGO).
Package postgres implements the s9l driver for PostgreSQL using the pure-Go jackc/pgx stdlib adapter (database/sql, no CGO).
driver/sqlite
Package sqlite implements the s9l driver for SQLite using the pure-Go modernc.org/sqlite driver (CGO-free), keeping cross-compilation and single-binary distribution intact.
Package sqlite implements the s9l driver for SQLite using the pure-Go modernc.org/sqlite driver (CGO-free), keeping cross-compilation and single-binary distribution intact.
driver/sqlserver
Package sqlserver implements the s9l driver for Microsoft SQL Server using the pure-Go microsoft/go-mssqldb adapter (database/sql, no CGO).
Package sqlserver implements the s9l driver for Microsoft SQL Server using the pure-Go microsoft/go-mssqldb adapter (database/sql, no CGO).
history
Package history persists query history and saved queries in a SQLite database at ~/.config/s9l/history.db (honoring $XDG_CONFIG_HOME).
Package history persists query history and saved queries in a SQLite database at ~/.config/s9l/history.db (honoring $XDG_CONFIG_HOME).
render
Package render formats query results for terminal output.
Package render formats query results for terminal output.
repl
Package repl provides the interactive read-eval-print loop: it reads lines from a LineReader, splits them into `;`-terminated statements, and dispatches each to an exec callback.
Package repl provides the interactive read-eval-print loop: it reads lines from a LineReader, splits them into `;`-terminated statements, and dispatches each to an exec callback.
schemacache
Package schemacache persists table/column names per connection in a SQLite database at ~/.cache/s9l/schema.db (honoring $XDG_CACHE_HOME).
Package schemacache persists table/column names per connection in a SQLite database at ~/.cache/s9l/schema.db (honoring $XDG_CACHE_HOME).
secret
Package secret abstracts credential storage behind a SecretStore interface, so connection passwords never live in config.yaml.
Package secret abstracts credential storage behind a SecretStore interface, so connection passwords never live in config.yaml.
tui
Package tui implements s9l's full-screen, lazygit-style terminal UI (Phase T).
Package tui implements s9l's full-screen, lazygit-style terminal UI (Phase T).
tunnel
Package tunnel forwards a local TCP port to a remote address through an SSH bastion, so s9l can reach a database that's only accessible from behind a jump host.
Package tunnel forwards a local TCP port to a remote address through an SSH bastion, so s9l can reach a database that's only accessible from behind a jump host.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL