About tblfmt

September 22, 2026 · View on GitHub

Package tblfmt provides streaming table encoders for result sets (ie, from a database), creating tables like the following:

 author_id | name                  | z
-----------+-----------------------+---
        14 | a	b	c	d  |
        15 | aoeu                 +|
           | test                 +|
           |                       |
        16 | foo\bbar              |
        17 | a	b	\r        +|
           | 	a                  |
        18 | 袈	袈		袈 |
        19 | 袈	袈		袈+| a+
           |                       |
(6 rows)

Additionally, there are standard encoders for JSON, CSV, HTML, unaligned and other display variants supported by usql.

Unit Tests Go Reference Discord Discussion

Installing

Install in the usual Go fashion:

$ go get -u github.com/xo/tblfmt

Using

tblfmt was designed for use by usql and Go's native database/sql types, but will handle any type with the following interface:

// ResultSet is the shared interface for a result set.
type ResultSet interface {
	Next() bool
	Scan(...interface{}) error
	Columns() ([]string, error)
	Close() error
	Err() error
	NextResultSet() bool
}

tblfmt can be used similar to the following:

// _example/example.go
package main

import (
	"log"
	"os"

	_ "github.com/lib/pq"
	"github.com/xo/dburl"
	"github.com/xo/tblfmt"
)

func main() {
	db, err := dburl.Open("postgres://booktest:booktest@localhost")
	if err != nil {
		log.Fatal(err)
	}
	defer db.Close()
	res, err := db.Query("select * from authors")
	if err != nil {
		log.Fatal(err)
	}
	defer res.Close()
	enc, err := tblfmt.NewTableEncoder(
		res,
		// force minimum column widths
		tblfmt.WithWidths(20, 20),
	)
	if err = enc.EncodeAll(os.Stdout); err != nil {
		log.Fatal(err)
	}
}

Which can produce output like the following:

╔══════════════════════╦═══════════════════════════╦═══╗
║ author_id            ║ name                      ║ z ║
╠══════════════════════╬═══════════════════════════╬═══╣
║                   14 ║ a	b	c	d  ║   ║
║                   15 ║ aoeu                     ↵║   ║
║                      ║ test                     ↵║   ║
║                      ║                           ║   ║
║                    2 ║ 袈	袈		袈 ║   ║
╚══════════════════════╩═══════════════════════════╩═══╝
(3 rows)

Please see the Go Reference for the full API.

Differences from psql

tblfmt follows psql's output closely. The differences below are deliberate; anything else is a bug worth reporting.

Trailing space on the last column

tblfmt pads the last column of a bordered table, so that every line of a table is the same width. psql pads the header but trims the data rows, leaving them ragged.

For select 42 as n, 'a'::text as t union all select 7, 'bb';, with trailing spaces written as · and the width of each line at the right:

psql 18.6                 tblfmt
 n  | t  ·         9       n  | t  ·         9
----+----          9      ----+----          9
 42 | a            7       42 | a ·          9
  7 | bb           8        7 | bb ·         9

psql is wrong here. A table whose lines do not share a width is awkward to select from a terminal, to diff, and to lay out in anything that measures the block, and the ragged edge carries no information. It is also inconsistent with psql's own header, which is padded. tblfmt will not follow it.

Testing

Run using standard go test:

$ go test -v