Embeddable database browser for Go: Bulma-styled HTML over a *sql.DB. Same code path on PostgreSQL and pglike (go-postgres), including in WASM.
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
Humphrey Drummond 1edad9c8ac Mark v0.1.0 release in CHANGELOG
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-10 09:30:16 +01:00
cmd/lofidb Initial release: embeddable DB browser library + CLI 2026-05-09 18:37:37 +01:00
examples/01_seeded_inmemory Use tagged go-postgres v0.5.4, drop replace directive 2026-05-10 08:46:25 +01:00
.gitignore Initial release: embeddable DB browser library + CLI 2026-05-09 18:37:37 +01:00
catalog.go Initial release: embeddable DB browser library + CLI 2026-05-09 18:37:37 +01:00
CHANGELOG.md Mark v0.1.0 release in CHANGELOG 2026-05-10 09:30:16 +01:00
go.mod Use tagged go-postgres v0.5.4, drop replace directive 2026-05-10 08:46:25 +01:00
go.sum Use tagged go-postgres v0.5.4, drop replace directive 2026-05-10 08:46:25 +01:00
index.md Initial release: embeddable DB browser library + CLI 2026-05-09 18:37:37 +01:00
LICENSE Initial release: embeddable DB browser library + CLI 2026-05-09 18:37:37 +01:00
lofidb.go Initial release: embeddable DB browser library + CLI 2026-05-09 18:37:37 +01:00
lofidb_test.go Initial release: embeddable DB browser library + CLI 2026-05-09 18:37:37 +01:00
README.md Initial release: embeddable DB browser library + CLI 2026-05-09 18:37:37 +01:00
ROADMAP.md Initial release: embeddable DB browser library + CLI 2026-05-09 18:37:37 +01:00
task-plus.yml Initial release: embeddable DB browser library + CLI 2026-05-09 18:37:37 +01:00
Taskfile.yml Initial release: embeddable DB browser library + CLI 2026-05-09 18:37:37 +01:00
wasm_soak_test.go Initial release: embeddable DB browser library + CLI 2026-05-09 18:37:37 +01:00

lofidb

A small, embeddable database browser for Go. Drop a *sql.DB into it and you get a Bulma-styled web UI that lists tables, shows their schema (columns, primary keys, foreign keys, indexes), and lets you page and sort through rows.

Works against:

  • PostgreSQL natively, via github.com/jackc/pgx/v5
  • pglike (codeberg.org/hum3/go-postgres) — a SQLite-backed driver that speaks PG SQL, so the same UI runs on a single in-memory *sql.DB with no external service
  • WASM: pglike runs under GOOS=wasip1 GOARCH=wasm, so lofidb can serve a fully in-browser DB browser via lofigui

A single set of PG-style information_schema queries powers everything — pglike installs PG-compatible catalog views per connection so the same SQL runs on either backend.

Install

go install codeberg.org/hum3/lofidb/cmd/lofidb@latest

Or import the library:

go get codeberg.org/hum3/lofidb

Quick start (CLI)

lofidb                                  # in-memory pglike scratchpad
lofidb file:/tmp/data.db                # browse a pglike on-disk file
lofidb postgres://localhost/myapp       # browse PostgreSQL
lofidb --addr :9000 file:/tmp/data.db   # custom port

Open the printed URL — by default http://localhost:8080/explorer.

Quick start (library)

package main

import (
    "database/sql"
    "log"
    "net/http"

    "codeberg.org/hum3/lofidb"
    _ "codeberg.org/hum3/go-postgres" // or _ "github.com/jackc/pgx/v5/stdlib"
)

func main() {
    db, _ := sql.Open("pglike", ":memory:")
    defer db.Close()

    // ... create tables, load data ...

    http.Handle("/explorer", lofidb.HTTPHandler(db, lofidb.Options{}))
    http.Handle("/explorer/", lofidb.HTTPHandler(db, lofidb.Options{}))
    log.Fatal(http.ListenAndServe(":8080", nil))
}

HTTPHandler mounts the index at the prefix and table-detail pages at <prefix>/<table>.

WASM mode

In WASM (e.g. via lofigui), call the HTML builders directly and pipe the strings into your renderer:

import "codeberg.org/hum3/lofigui"

lofigui.Reset()
lofigui.HTML(lofidb.IndexHTML(db, lofidb.Options{}))
// or, for a specific table:
lofigui.HTML(lofidb.TableHTML(db, "users", page, sort, dir, lofidb.Options{}))

The builders are pure functions: they take a *sql.DB and return an HTML fragment. The sample example under examples/ runs an entire pglike DB plus this UI in the browser.

Options

type Options struct {
    Schema     string   // default "public"
    URLPrefix  string   // default "/explorer"
    PageSize   int      // default 50
    HideTables []string // tables to hide in addition to internal ones
}

Schema is "public" for both PostgreSQL (default) and pglike (which reports 'public' from its catalog views and current_schema()). For multi-schema PostgreSQL setups, set this to the schema you want to browse.

How it works

The HTML pages render from a small set of catalog queries:

Information Query target
Table list information_schema.tables
Column info information_schema.columns
Primary keys information_schema.table_constraintsinformation_schema.key_column_usage
Foreign keys information_schema.referential_constraintskey_column_usageconstraint_column_usage
Indexes pg_indexes (+ pglike-specific pg_index_columns for column lists)

These views exist natively in PostgreSQL. pglike installs TEMP VIEW shims with the same names and shapes per connection, so the queries are unchanged across backends.

For index columns, lofidb prefers a pg_index_columns helper view that pglike exposes. Real PostgreSQL doesn't expose this view by default — the index list still shows up, but column lists may be empty until you create an equivalent helper view. (See examples/02_postgres_index_columns_view.sql.)

Data-size testing

wasm_soak_test.go measures how much data fits in a pglike :memory: database under WASM. It runs natively or under wasip1+wazero and emits JSON-line metrics. Run:

# native (sanity check)
WASM_SOAK_ROWS=100000 task test
# wasm (real measurement)
task test:wasm:soak WASM_SOAK_ROWS=200000
# capture metrics
task test:wasm:soak WASM_SOAK_ROWS=500000 WASM_SOAK_OUTPUT=wasm-soak.jsonl

Each line is one of:

{"stage":"start", "target_rows":N,"batch_size":B,"heap_alloc_mb":...}
{"stage":"progress","inserted_rows":N,"wall_secs":...,"heap_alloc_mb":...,"batch_latency_secs":...}
{"stage":"done",  "inserted_rows":N,"wall_secs":...,"heap_alloc_mb":...}

A single representative row is ~120 bytes (id + 80-byte payload + timestamp + 10-byte key); WASM heap is dominated by SQLite's page cache and Go's GC. Initial measurements on wazero put the practical ceiling between 200k and 1M rows per :memory: DB before the WASM module hits its memory limit; results vary by browser engine and module config. The harness records the last successful batch on OOM so you can chart the curve rather than just "it crashed".

Development

task check        # fmt + vet + test
task build        # build cmd/lofidb
task test:wasm    # run tests under wasip1/wasm
Documentation https://h3-lofidb.statichost.page/
Source (Codeberg) https://codeberg.org/hum3/lofidb
Mirror (GitHub) https://github.com/drummonds/lofidb

License

MIT