Skip to content

Go SDK

Go SDK

Recommended: github.com/jackc/pgx/v5 (direct PG wire) or github.com/dimensigon/heliosdb-sdks/go (REST/Realtime client) Repo: heliosdb-sdks Compatible with: all HeliosDB editions (Nano, Lite, Full)


UVP

There is no in-process Go embedding API for HeliosDB Nano — the engine is Rust. That’s by design: the Nano binary speaks the PostgreSQL v3 wire protocol natively, so every battle-tested Go driver (pgx, lib/pq, database/sql, GORM, ent) connects with zero adapters. For services that prefer the REST/Realtime BaaS surface, the official heliosdb-sdks/go package wraps the same db.From("table").Select() fluent API you’d find in the JS / Python SDKs. No CGo. No FFI. Just idiomatic Go.


Path A — Direct PG Wire (pgx)

The first-choice path for Go services. Battle-tested driver, prepared statements, connection pooling, full SQL surface.

Install

Terminal window
go get github.com/jackc/pgx/v5@latest

Connect

package main
import (
"context"
"fmt"
"log"
"github.com/jackc/pgx/v5"
)
const dsn = "postgresql://postgres:s3cret@127.0.0.1:5432/postgres"
func main() {
ctx := context.Background()
conn, err := pgx.Connect(ctx, dsn)
if err != nil {
log.Fatal(err)
}
defer conn.Close(ctx)
var v string
if err := conn.QueryRow(ctx, "SELECT version()").Scan(&v); err != nil {
log.Fatal(err)
}
fmt.Println(v)
}

CRUD

type Product struct {
ID int
Name string
Price float64
}
// Schema (one-time)
_, err := conn.Exec(ctx, `
CREATE TABLE IF NOT EXISTS products (
id SERIAL PRIMARY KEY,
name TEXT NOT NULL,
price NUMERIC(10, 2)
)`)
// Insert
var id int
err = conn.QueryRow(ctx,
`INSERT INTO products (name, price) VALUES ($1, $2) RETURNING id`,
"Widget", 9.99,
).Scan(&id)
// Read
rows, err := conn.Query(ctx,
`SELECT id, name, price FROM products WHERE price < $1 ORDER BY id`, 50.0)
defer rows.Close()
for rows.Next() {
var p Product
rows.Scan(&p.ID, &p.Name, &p.Price)
fmt.Println(p)
}
// Update
_, err = conn.Exec(ctx, `UPDATE products SET price = $1 WHERE id = $2`, 12.99, id)
// Delete
_, err = conn.Exec(ctx, `DELETE FROM products WHERE id = $1`, id)

Connection Pool

For HTTP services use pgxpool:

import "github.com/jackc/pgx/v5/pgxpool"
pool, err := pgxpool.New(ctx, dsn)
defer pool.Close()
// Use pool.Query / pool.Exec / pool.QueryRow exactly like *pgx.Conn

Transactions

tx, _ := conn.Begin(ctx)
defer tx.Rollback(ctx) // no-op if Commit succeeds
_, err = tx.Exec(ctx, "UPDATE accounts SET balance = balance - $1 WHERE id = $2", 100, fromID)
if err != nil { return err }
_, err = tx.Exec(ctx, "UPDATE accounts SET balance = balance + $1 WHERE id = $2", 100, toID)
if err != nil { return err }
return tx.Commit(ctx)

VECTOR(n) accepts the standard text literal '[v1,v2,...]' over the wire; we marshal []float32 to that form:

import (
"strconv"
"strings"
)
func vecLit(v []float32) string {
parts := make([]string, len(v))
for i, f := range v {
parts[i] = strconv.FormatFloat(float64(f), 'f', 6, 32)
}
return "[" + strings.Join(parts, ",") + "]"
}
// Schema
conn.Exec(ctx, `
CREATE TABLE IF NOT EXISTS docs (
id SERIAL PRIMARY KEY,
title TEXT,
embedding VECTOR(384)
);
CREATE INDEX IF NOT EXISTS docs_emb_idx
ON docs USING hnsw (embedding vector_cosine_ops);`)
// Insert
emb := make([]float32, 384) // populate from your embedder
conn.Exec(ctx,
`INSERT INTO docs (title, embedding) VALUES ($1, $2::vector)`,
"Helios release", vecLit(emb))
// k-NN
qVec := make([]float32, 384) // query vector
rows, _ := conn.Query(ctx,
`SELECT id, title, embedding <=> $1::vector AS distance
FROM docs ORDER BY distance LIMIT $2`,
vecLit(qVec), 10)
defer rows.Close()
for rows.Next() {
var id int
var title string
var dist float64
rows.Scan(&id, &title, &dist)
fmt.Printf("%.4f %s\n", dist, title)
}

Distance operators:

OperatorDistanceUse case
<=>CosineNormalized text/sentence embeddings
<->L2Image / unnormalized vectors
<#>Negative inner productAlready-normalized, speed-critical

database/sql (standard library)

If you prefer the stdlib interface, pgx ships a stdlib adapter:

import (
"database/sql"
_ "github.com/jackc/pgx/v5/stdlib"
)
db, _ := sql.Open("pgx", dsn)
defer db.Close()
rows, _ := db.QueryContext(ctx, "SELECT id, name FROM users WHERE id = $1", 42)

GORM and ent ride on top of database/sql, so they work unchanged.


Path B — REST/Realtime SDK (heliosdb-sdks/go)

For services that prefer the BaaS surface (auth, RLS-aware reads, WebSocket subscriptions). Same fluent API as the JS / Python SDKs.

Install

Terminal window
go get github.com/dimensigon/heliosdb-sdks/go

Connect + Login

import helios "github.com/dimensigon/heliosdb-sdks/go"
client := helios.NewClient("http://localhost:8080", "anon-key")
defer client.Close()
session, err := client.Auth().SignInWithPassword(ctx, helios.Credentials{
Email: "alice@example.com",
Password: "s3cret",
})

CRUD

// Insert
result, _ := client.From("posts").Insert(ctx, map[string]any{
"title": "Hello",
"body": "First post",
}).Select().Execute()
// Read
var posts []Post
_, _ = client.From("posts").
Select("id, title, body").
Eq("author", "alice@example.com").
Order("created_at", helios.OrderDesc).
Limit(10).
ExecuteInto(ctx, &posts)
// Update
client.From("posts").Update(ctx, map[string]any{"body": "edited"}).Eq("id", 1).Execute()
// Delete
client.From("posts").Delete(ctx).Eq("id", 1).Execute()

Vector Search

results, err := client.VectorSearch(ctx, "docs", queryVec, &helios.VectorSearchOptions{
TopK: 10,
Metric: helios.MetricCosine,
Filter: map[string]any{"category": "tech"},
})
for _, hit := range results {
fmt.Println(hit.ID, hit.Score, hit.Row["title"])
}

Realtime

ch, _ := client.Channel("posts-changes").
OnPostgresChanges(helios.PostgresChangesFilter{
Event: helios.EventAll, Schema: "public", Table: "posts",
}, func(payload helios.ChangePayload) {
fmt.Println(payload.EventType, payload.New)
}).
Subscribe(ctx)
defer ch.Unsubscribe()

When to Pick Which

NeedUse
Backend service, heavy SQLPath A (pgx)
GORM / ent / sqlxPath A
Bulk imports (COPY FROM)Path A
Multi-tenant app with JWT-RLSPath B
WebSocket realtime subscriptionsPath B
Drop-in Supabase migrationPath B

Both paths can share the same Nano server; data written via pgx is immediately visible through the SDK and vice versa.


Next Steps