Ruby
One import, one connection. Microsecond reads from L1 cache.
Install
gem install goldlapel
# or in your Gemfile
gem "goldlapel"
# You also need a Postgres driver — pg is the most common:
gem "pg" Gold Lapel is driver-agnostic — install whichever Postgres driver you prefer (pg is typical) and point it at gl.url.
Quick Start
Sync
require "goldlapel"
require "pg"
# Spawn the proxy in front of your upstream DB — returns a GoldLapel instance
gl = GoldLapel.start("postgresql://user:pass@localhost:5432/mydb", proxy_port: 7932)
# Use gl.url with any Postgres driver for raw SQL
conn = PG.connect(gl.url)
conn.exec_params("SELECT * FROM users WHERE id = $1", [42])
# Or use Gold Lapel's wrapper methods directly — no conn arg needed
hits = gl.search("articles", "body", "postgres tuning")
gl.doc_insert("events", type: "signup", user: "steve")
# Clean up (also runs automatically on process exit)
gl.stop Repeated reads serve in microseconds from the built-in L1 cache.
Async
Use GoldLapel::Async inside an Async reactor from the async gem. Install separately — the async gem is not a hard dependency of goldlapel, so require "goldlapel/async" fails with a clear message if it isn't present.
require "goldlapel/async"
require "async"
Async do
gl = GoldLapel::Async.start("postgresql://user:pass@localhost:5432/mydb")
hits = gl.search("articles", "body", "postgres tuning")
gl.doc_insert("events", type: "signup")
gl.stop
end v0.2.0 caveat: the async API shape is stable, but the underlying IO is still blocking under the hood. Native async-pg integration lands in v0.2.1.
Gold Lapel prints the proxy and dashboard URLs on startup to $stderr. Access the dashboard programmatically:
gl.dashboard_url # "http://127.0.0.1:7933" (or nil if disabled / not running) Banner goes to $stderr so it never pollutes $stdout-piped application output. Pass silent: true to GoldLapel.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 connection via gl.using(conn) do |gl| ... end (scoped) or the conn: keyword (per call):
require "pg"
gl = GoldLapel.start("postgresql://...")
conn = PG.connect(gl.url)
conn.exec("BEGIN")
# Scoped: every wrapper call in this block uses `conn`
gl.using(conn) do |gl|
gl.doc_insert("events", type: "order.created")
gl.incr("counters", "orders")
end
conn.exec("COMMIT")
# Or per-call
gl.doc_insert("events", { type: "x" }, conn: conn) The block form is the idiomatic Ruby shape — every wrapper call inside the block binds to conn. For one-off overrides, pass conn: as the last keyword argument on any wrapper method.
API
gl = GoldLapel.start(upstream, proxy_port: nil, dashboard_port: nil, invalidation_port: nil, log_level: nil, mode: nil, license: nil, client: nil, config_file: nil, config: {}, extra_args: [], silent: false, mesh: false, mesh_tag: nil)
Factory that spawns the proxy and returns a GoldLapel instance. Eagerly opens the wrapper's internal pg connection so wrapper methods are fast from the first call.
upstream— your Postgres connection string (e.g.postgresql://user:pass@localhost:5432/mydb)proxy_port:— proxy port (default: 7932)dashboard_port:— dashboard port (default:proxy_port + 1; set to0to disable)invalidation_port:— cache-invalidation port (default:proxy_port + 2)log_level:— one oftrace | debug | info | warn | errormode:— operating mode (waiter,bellhop)license:— path to the signed license fileclient:— client identifier for telemetry tagging (defaults to"ruby")config_file:— path to a TOML config file read by the Rust binaryconfig:— hash of structured tuning knobs (seeGoldLapel.config_keys)extra_args:— additional raw CLI flags (e.g.["--threshold-impact", "5000"])silent:— suppress the$stderrstartup banner (default:false)mesh:— opt into the mesh at startup (HQ enforces the license; denial is non-fatal)mesh_tag:— optional mesh tag; instances sharing a tag cluster together
Promoted top-level kwargs are not valid keys inside config: — passing them there raises ArgumentError.
GoldLapel::Async.start(upstream, ...)
Async factory. Same signature as the sync factory but intended for use inside an Async reactor. Requires require "goldlapel/async" and the async gem.
gl.url
Proxy connection string — pass to any Postgres driver.
gl.dashboard_url
Dashboard URL (e.g. http://127.0.0.1:7933), or nil if not running or the dashboard is disabled.
gl.using(conn) { |gl| ... }
Block form that scopes every wrapper call inside the block to conn. All wrapper methods also accept a conn: keyword for one-off overrides.
gl.stop
Stops the proxy and closes the internal connection. Idempotent. Also runs automatically on process exit.
GoldLapel.config_keys
Returns an array of all valid config key names.
require "goldlapel"
puts GoldLapel.config_keys Multiple instances
GoldLapel.start is a factory — each call spawns its own proxy subprocess and returns a fresh instance. Use different ports to run several side by side.
# Each GoldLapel.start call returns a fresh instance on its own port
gl_primary = GoldLapel.start("postgresql://primary/mydb", proxy_port: 7932)
gl_replica = GoldLapel.start("postgresql://replica/mydb", proxy_port: 7942)
gl_primary.search("articles", "body", "query") # hits primary
gl_replica.search("articles", "body", "query") # hits replica
gl_primary.stop
gl_replica.stop Configuration
Pass a config: hash to start. Keys use snake_case symbols or strings and map directly to CLI flags (pool_size → --pool-size). The log_level key accepts string levels (trace / debug / info / warn / error) and translates to the binary's verbose flags internally.
require "goldlapel"
gl = GoldLapel.start(
"postgresql://user:pass@localhost/mydb",
mode: "waiter", # top-level: waiter | bellhop
log_level: "info", # top-level: trace | debug | info | warn | error
mesh: true, # top-level: opt into the mesh at startup
mesh_tag: "prod-east", # top-level: optional mesh tag
config: { # structured tuning knobs only
pool_size: 50,
disable_matviews: true,
replica: ["postgresql://user:pass@replica1/mydb"],
},
) Unknown keys raise ArgumentError immediately. There is a configuration reference covering every available setting.
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.
Framework integrations
Gold Lapel is driver-agnostic, so any Ruby framework that speaks to Postgres just works against gl.url.
- Rails — integration code ships inside the
goldlapelgem. Addrequire "goldlapel/rails"to your initializer and pointdatabase.ymlatgl.url. See the Rails guide. - Sinatra / Sequel / plain Ruby — use
GoldLapel.startdirectly withpgand handgl.urlto whatever speaks Postgres. - Async Ruby — use
GoldLapel::Async.startinside anAsyncreactor.
Upgrading from v0.1
v0.2 is a breaking redesign. The class-based GoldLapel.new(url).start shape (which returned a wrapped connection) is replaced by a GoldLapel.start(url) factory that returns a GoldLapel instance. Bring your own driver and point it at gl.url.
# v0.1.x (old) — class constructor + start returns a connection
gl = GoldLapel.new("postgresql://...")
conn = gl.start
conn.exec("SELECT 1")
gl.stop
# v0.2 (new) — factory returns an instance, bring your own driver
require "pg"
gl = GoldLapel.start("postgresql://...")
conn = PG.connect(gl.url)
conn.exec("SELECT 1")
gl.stop
# v0.1 async (old) — not available
# v0.2 async — separate submodule, opt-in require
require "goldlapel/async"
Async do
gl = GoldLapel::Async.start("postgresql://...")
gl.stop
end GoldLapel.start(url)returns aGoldLapelinstance (previouslyGoldLapel.new(url).startreturned a connection).- Module name is now
GoldLapel(lower-casel) — matches the gem name. - Bring your own
pgconnection againstgl.urlinstead of using the one returned fromstart. - Async is a separate opt-in:
require "goldlapel/async"and theasyncgem (not a hard dep). - All wrapper methods now accept an optional
conn:keyword, andgl.using(conn) do |gl| ... endprovides scoped override. - 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 conn: keyword for transactional coordination.
Pub/Sub
# Pub/Sub — backed by PostgreSQL LISTEN/NOTIFY
gl.publish("orders", "new order")
gl.subscribe("orders") { |msg| puts msg } Queues
# Queues — backed by FOR UPDATE SKIP LOCKED
gl.enqueue("jobs", { task: "send_email" })
job = gl.dequeue("jobs") Counters
# Counters — backed by INSERT ON CONFLICT
gl.incr("page_views", "home")
count = gl.get_counter("page_views", "home") Sorted Sets
# Sorted Sets — backed by ORDER BY and window functions
gl.zadd("leaderboard", "player1", 100)
top = gl.zrange("leaderboard", 0, 9) Streams
# Streams — append-only log with consumer groups
id = gl.stream_add("events", { type: "signup" })
gl.stream_create_group("events", "workers")
msgs = gl.stream_read("events", "workers", "worker-1")
gl.stream_ack("events", "workers", msgs[0].id) See the Redis Replacement docs for the complete API — including geospatial, rate limiting, sessions, and scripting.
Document Store
doc_find, doc_insert, doc_update, doc_delete and friends operate on JSONB-backed collections. Tables are auto-created on first use.
Filter operators
doc_find 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 = gl.doc_find("orders", {
items: { "$elemMatch" => { sku: "ABC-123", qty: { "$gte" => 2 } } }
}) # $text — full-text search, document-wide or field-scoped
hits = gl.doc_find("articles", {
"$text" => { "$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 = gl.facets("articles", "category")
filtered = gl.facets("articles", "category",
query: "machine learning", query_column: "body") Aggregations
# Aggregations — count, sum, avg, min, max with optional grouping
by_region = gl.aggregate("orders", "total", "avg", group_by: "region") Custom Search Config
# Custom search config
gl.create_search_config("my_english", copy_from: "english") Percolator
Store queries, then match documents against them. Like Elasticsearch percolate.
# Percolator — store queries, match documents against them
gl.percolate_add("alerts", "breaking-news",
"breaking news earthquake", metadata: { notify: "slack" })
matches = gl.percolate("alerts",
"A 6.2 magnitude earthquake struck the coast.")
gl.percolate_delete("alerts", "breaking-news") Analyze
# Analyze — show tokenization pipeline
tokens = gl.analyze("The quick brown foxes") Explain Score
# Explain score — score breakdown for a specific document
result = gl.explain_score("articles", "body",
"machine learning", "id", 42) See the API reference for full parameter details on all search methods.