Go
One import, one connection. Microsecond reads from L1 cache.
Install
go get github.com/goldlapel/goldlapel-go
// You also need a Postgres driver — either works:
go get github.com/jackc/pgx/v5 // pgx (recommended)
go get github.com/lib/pq // or lib/pq Gold Lapel is driver-agnostic — Go's database/sql abstraction works with both pgx (recommended) and lib/pq. Pick whichever you prefer and point it at gl.URL().
Quick Start
package main
import (
"context"
"database/sql"
"log"
_ "github.com/jackc/pgx/v5/stdlib" // or _ "github.com/lib/pq"
"github.com/goldlapel/goldlapel-go"
)
func main() {
ctx := context.Background()
// Spawn the proxy — returns a *GoldLapel instance
gl, err := goldlapel.Start(ctx, "postgresql://user:pass@localhost:5432/mydb",
goldlapel.WithProxyPort(7932),
goldlapel.WithLogLevel("info"),
)
if err != nil {
log.Fatal(err)
}
defer gl.Close()
// Use gl.URL() with any database/sql driver for raw SQL
db, err := sql.Open("pgx", gl.URL())
if err != nil {
log.Fatal(err)
}
rows, err := db.QueryContext(ctx, "SELECT * FROM users WHERE id = $1", 42)
if err != nil {
log.Fatal(err)
}
defer rows.Close()
// Or use Gold Lapel's wrapper methods directly — ctx first, no conn arg needed
hits, _ := gl.Search(ctx, "articles", "body", "postgres tuning")
_ = gl.DocInsert(ctx, "events", map[string]any{"type": "signup"})
_ = hits
} Repeated reads serve in microseconds from the built-in L1 cache.
After startup, Gold Lapel prints a one-line summary to stderr and serves a dashboard:
gl.DashboardURL()
// => "http://127.0.0.1:7933" (or "" if not running / dashboard disabled) Banner goes to stderr so it never pollutes stdout-piped application output. Pass goldlapel.WithSilent(true) to Start to suppress it entirely — useful for daemons and structured-log pipelines that inspect both streams.
Transactional coordination
When you want wrapper methods to run inside your own transaction, pass your *sql.Tx via gl.InTx(ctx, tx, fn) (scoped closure) or the WithTx option (per call):
// Scoped: every wrapper call inside the closure uses `tx`
tx, err := db.BeginTx(ctx, nil)
if err != nil {
log.Fatal(err)
}
err = gl.InTx(ctx, tx, func(gl *goldlapel.GoldLapel) error {
if err := gl.DocInsert(ctx, "events", map[string]any{"type": "order.created"}); err != nil {
return err
}
return gl.Incr(ctx, "counters", "orders")
})
if err != nil {
tx.Rollback()
log.Fatal(err)
}
tx.Commit()
// Or per-call via WithTx
err = gl.DocInsert(ctx, "events", map[string]any{"type": "x"},
goldlapel.WithTx(tx),
) The closure form is the idiomatic Go shape — every wrapper call inside the closure binds to tx. For one-off overrides, pass goldlapel.WithTx(tx) as the final variadic option on any wrapper method.
API
goldlapel.Start(ctx context.Context, upstream string, opts ...Option) (*GoldLapel, error)
Factory that spawns the proxy and returns a *GoldLapel. Eagerly opens the wrapper's internal driver connection so wrapper methods are fast from the first call.
ctx— cancellation context for startup and internal connectionupstream— your Postgres connection string (e.g.postgresql://user:pass@localhost:5432/mydb)opts— functional options:WithProxyPort,WithLogLevel,WithConfig,WithExtraArgs
gl.URL() string
Proxy connection string — pass to sql.Open("pgx", gl.URL()) (or "postgres" for lib/pq).
gl.DashboardURL() string
Dashboard URL (e.g. http://127.0.0.1:7933), or "" if not running or the dashboard is disabled.
gl.InTx(ctx, tx, func(gl *GoldLapel) error) error
Runs the closure with tx as the implicit transaction for every wrapper method invoked inside. Every wrapper method also accepts a trailing goldlapel.WithTx(tx) option for one-off overrides.
gl.Close() error
Stops the proxy and closes the internal connection. Idempotent. Wire it with defer gl.Close() for guaranteed cleanup.
gl.ProxyPort() int
Returns the port the proxy is listening on.
gl.Running() bool
Returns whether the proxy instance is currently running.
goldlapel.ConfigKeys() []string
Returns all valid config key names.
keys := goldlapel.ConfigKeys()
fmt.Println(keys) Functional options
goldlapel.WithProxyPort(port int)— proxy port (default: 7932)goldlapel.WithDashboardPort(port int)— dashboard port (default:proxy_port + 1; set to0to disable)goldlapel.WithInvalidationPort(port int)— cache-invalidation port (default:proxy_port + 2)goldlapel.WithLogLevel(level string)—trace/debug/info/warn/error(translated to verbose flags internally)goldlapel.WithMode(mode string)— operating mode (waiter,bellhop)goldlapel.WithLicense(path string)— path to the signed license filegoldlapel.WithClient(name string)— client identifier for telemetry tagging (defaults to"go")goldlapel.WithConfigFile(path string)— path to a TOML config file read by the Rust binarygoldlapel.WithConfig(config map[string]any)— structured tuning knobs only (snake_case keys →--pool-sizestyle flags)goldlapel.WithExtraArgs(args ...string)— raw CLI flags passed to the binarygoldlapel.WithSilent(silent bool)— suppress thestderrstartup banner (default: off)goldlapel.WithMesh(mesh bool)— opt into the mesh at startup (HQ enforces the license; denial is non-fatal)goldlapel.WithMeshTag(tag string)— optional mesh tag; instances sharing a tag cluster togethergoldlapel.WithTx(tx *sql.Tx)— per-call transaction override on any wrapper method
Promoted top-level options (WithProxyPort, WithDashboardPort, WithLogLevel, WithMode, etc.) must be passed as functional options — they are not valid keys inside WithConfig and will cause Start to return an error if present.
Multiple instances
Each Start call spawns its own proxy subprocess and returns a fresh *GoldLapel. Use different ports to run several side by side.
// Each Start call returns a fresh instance on its own port
gl1, _ := goldlapel.Start(ctx, "postgresql://user:pass@localhost:5432/app_db",
goldlapel.WithProxyPort(7932),
)
gl2, _ := goldlapel.Start(ctx, "postgresql://user:pass@localhost:5432/analytics_db",
goldlapel.WithProxyPort(7942),
)
// Each instance manages its own proxy and cache
defer gl1.Close()
defer gl2.Close() Configuration
Pass a map[string]any via WithConfig. Keys use snake_case and map directly to CLI flags (pool_size → --pool-size). The WithLogLevel option accepts string levels and translates to the binary's verbose flags internally.
gl, err := goldlapel.Start(ctx, "postgresql://user:pass@localhost/mydb",
goldlapel.WithLogLevel("info"), // top-level
goldlapel.WithMode("waiter"), // top-level (promoted out of config)
goldlapel.WithMesh(true), // top-level: opt into the mesh at startup
goldlapel.WithMeshTag("prod-east"), // top-level: optional mesh tag
goldlapel.WithConfig(map[string]any{ // structured tuning knobs only
"pool_size": 50,
"disable_matviews": true,
"replica": []string{"postgresql://user:pass@replica1/mydb"},
}),
) Unknown keys return an error immediately. The configuration reference has the complete list of valid keys.
Raw CLI flags
You can also pass raw CLI flags via WithExtraArgs:
gl, err := goldlapel.Start(ctx, "postgresql://user:pass@localhost:5432/mydb",
goldlapel.WithExtraArgs("--threshold-duration-ms", "200", "--refresh-interval-secs", "30"),
) Environment variables
The binary also reads GOLDLAPEL_PROXY_PORT, GOLDLAPEL_UPSTREAM, and all other GOLDLAPEL_* env vars automatically. Set GOLDLAPEL_BINARY to override the binary location.
Driver-agnostic
Gold Lapel works with any Postgres driver that speaks database/sql. The two common choices:
pgx— recommended.import _ "github.com/jackc/pgx/v5/stdlib"thensql.Open("pgx", gl.URL()). Faster binary protocol; richer type support.lib/pq— older, still widely used.import _ "github.com/lib/pq"thensql.Open("postgres", gl.URL()).
Concurrency is handled the idiomatic Go way — spin up goroutines, share the *GoldLapel. There's no separate async flavor.
Upgrading from v0.1
v0.2 is a breaking redesign. The two-step goldlapel.New(url) + gl.Start() pattern (which returned a *sql.DB) is replaced by a one-call goldlapel.Start(ctx, url, opts...) factory that returns a *GoldLapel. Bring your own driver and point it at gl.URL().
// v0.1 (old) — constructor + Start returned a *sql.DB
gl := goldlapel.New("postgresql://...")
db, err := gl.Start()
defer gl.Stop()
_, _ = db.Query("SELECT 1")
// v0.2 (new) — factory takes ctx + options, bring your own driver
import _ "github.com/jackc/pgx/v5/stdlib"
ctx := context.Background()
gl, err := goldlapel.Start(ctx, "postgresql://...",
goldlapel.WithProxyPort(7932),
)
defer gl.Close()
db, _ := sql.Open("pgx", gl.URL())
_, _ = db.QueryContext(ctx, "SELECT 1") goldlapel.Start(ctx, url, opts...)replaces theNew+Startpair and now takesctxas the first argument.- Wrapper methods take
ctx context.Contextas their first argument. gl.Close()replacesgl.Stop()(pairs naturally withdeferandio.Closer).- Bring your own
*sql.DBagainstgl.URL()instead of using the one returned fromStart. - New
WithLogLeveloption accepts string levels. - New
WithTxoption works on every wrapper method;gl.InTxprovides a scoped closure form. - Multiple instances are first-class — each
Startcall spawns its own proxy.
Redis Replacement
Gold Lapel includes a Redis Replacement API — common Redis patterns backed by PostgreSQL. Every method hangs directly off gl and accepts an optional trailing goldlapel.WithTx(tx) option for transactional coordination.
Pub/Sub
// Pub/Sub — backed by PostgreSQL LISTEN/NOTIFY
_ = gl.Publish(ctx, "orders", "new order")
_ = gl.Subscribe(ctx, "orders", func(msg string) {
fmt.Println(msg)
}) Queues
// Queues — backed by FOR UPDATE SKIP LOCKED
_ = gl.Enqueue(ctx, "jobs", map[string]any{"task": "send_email"})
job, _ := gl.Dequeue(ctx, "jobs") Counters
// Counters — backed by INSERT ON CONFLICT
_ = gl.Incr(ctx, "page_views", "home")
count, _ := gl.GetCounter(ctx, "page_views", "home") Sorted Sets
// Sorted Sets — backed by ORDER BY and window functions
_ = gl.Zadd(ctx, "leaderboard", "player1", 100)
top, _ := gl.Zrange(ctx, "leaderboard", 0, 9) Streams
// Streams — append-only log with consumer groups
id, _ := gl.StreamAdd(ctx, "events", map[string]any{"type": "signup"})
_ = gl.StreamCreateGroup(ctx, "events", "workers")
msgs, _ := gl.StreamRead(ctx, "events", "workers", "worker-1")
_ = gl.StreamAck(ctx, "events", "workers", msgs[0].ID)
_ = id See the Redis Replacement docs for the complete API — including geospatial, rate limiting, sessions, and scripting.
Document Store
DocFind, DocInsert, DocUpdate, DocDelete and friends operate on JSONB-backed collections. Tables are auto-created on first use.
Filter operators
DocFind supports the MongoDB filter operators you'd reach for — $elemMatch, $text, $gt, $in, and more.
// $elemMatch — scope multi-condition filters to a single array element
orders, err := gl.DocFind(ctx, "orders", map[string]any{
"items": map[string]any{
"$elemMatch": map[string]any{"sku": "ABC-123", "qty": map[string]any{"$gte": 2}},
},
}) // $text — full-text search, document-wide or field-scoped
hits, err := gl.DocFind(ctx, "articles", map[string]any{
"$text": map[string]any{"$search": "postgres tuning"},
}) See Appendix D: Filter Operator Reference for the full list, Postgres translations, and index notes.
Search
Full-text search utilities backed by PostgreSQL tsvector/tsquery. No extensions required.
Facets
// Facets — value counts, optionally filtered by a search query
results, err := gl.Facets(ctx, "articles", "category", nil)
filtered, err := gl.Facets(ctx, "articles", "category", &goldlapel.FacetsOpts{
Query: "machine learning", QueryColumn: "body",
}) Aggregations
// Aggregations — count, sum, avg, min, max with optional grouping
byRegion, err := gl.Aggregate(ctx, "orders", "total", "avg", &goldlapel.AggregateOpts{
GroupBy: "region",
}) Custom Search Config
// Custom search config
err := gl.CreateSearchConfig(ctx, "my_english", &goldlapel.SearchConfigOpts{
CopyFrom: "english",
}) Percolator
Store queries, then match documents against them. Like Elasticsearch percolate.
// Percolator — store queries, match documents against them
err := gl.PercolateAdd(ctx, "alerts", "breaking-news",
"breaking news earthquake", &goldlapel.PercolateAddOpts{
Metadata: map[string]any{"notify": "slack"},
})
matches, err := gl.Percolate(ctx, "alerts",
"A 6.2 magnitude earthquake struck the coast.", nil)
deleted, err := gl.PercolateDelete(ctx, "alerts", "breaking-news") Analyze
// Analyze — show tokenization pipeline
tokens, err := gl.Analyze(ctx, "The quick brown foxes", nil) Explain Score
// Explain score — score breakdown for a specific document
result, err := gl.ExplainScore(ctx, "articles", "body",
"machine learning", "id", 42, nil) See the API reference for full parameter details on all search methods.