Reference
Go SDK Reference
One-page reference for common Onyx SDK calls. Select a language to see the syntax.
Onyx Environment Variables
Set these to control how the SDK scopes requests and where it fetches credentials.
| Env Var | Description | Default |
|---|---|---|
| ONYX_DATABASE_ID | Database UUID used to scope requests; required. | none |
| ONYX_DATABASE_BASE_URL | HTTP base for DB API. | https://api.onyx.dev |
| ONYX_DATABASE_API_KEY | API key for the database; required. | none |
| ONYX_DATABASE_API_SECRET | API secret for the database; required. | none |
| ONYX_AI_BASE_URL | Base URL for AI/chat endpoints. | https://ai.onyx.dev |
| ONYX_DEFAULT_MODEL | Model used by db.chat() shorthand. | onyx |
| ONYX_CONFIG_PATH | Path to JSON credentials file (Node only; ignored on edge). | unset |
| ONYX_DEBUG | When "true", enables request/response logging and config debug output. | false |
| ONYX_STREAM_DEBUG | When "true"/"1", logs streaming connection details. | false |
Initialization Patterns
Initialize the Go SDK with explicit config or environment resolution.
Auto resolution
Resolves credentials from env vars, then onyx-database.json in the project/home directories.
ctx := context.Background()
db, err := onyx.New(ctx, onyx.Config{})
Initialize with config object
Pass credentials directly when you can’t rely on env/file resolution.
ctx := context.Background()
db, err := onyx.New(ctx, onyx.Config{
ApiKey: "YOUR_API_KEY",
ApiSecret: "YOUR_API_SECRET"
})
Optional config fields
| Attribute | Description | Default |
|---|---|---|
| baseUrl | REST base URL for database operations. | https://api.onyx.dev |
| databaseId | Database ID (inferred from DB-scoped keys; set for org-wide keys). | resolved from key |
| aiBaseUrl | Base URL for AI endpoints. | https://ai.onyx.dev |
| defaultModel | Fallback AI model for shorthand chat calls. | onyx |
| partition | Default partition for queries/find/delete. | entity partition |
| ttl | Millis to cache resolved credentials. | 300000 |
| retry | Retry config for idempotent GETs. | 3 retries; 300/600/1200ms |
Core CRUD
Upsert, fetch, update, and delete entities by primary key.
ctx := context.Background()
db, err := onyx.New(ctx, onyx.Config{})
acct := &onyx.Account{Id: "acct_1", Name: "Checking", Balance: 1250}
err = db.Accounts().Save(ctx, acct)
found, err := db.Accounts().Find(ctx, "acct_1")
fmt.Println(found, err)
acct.Balance = 1400
err = db.Accounts().Save(ctx, acct)
err = db.Accounts().Delete(ctx, "acct_1")Atomic Saving
Persist a parent plus related records in one call—no explicit transactions needed.
Cascade save
Save an Account and its Transactions together; all-or-none commit.
acct := &onyx.Account{
Id: "acct_cascade",
Name: "Primary",
Balance: 0,
Transactions: []onyx.Transaction{
{Id: "txn_1", AccountId: "acct_cascade", Amount: 250, Currency: "USD"},
{Id: "txn_2", AccountId: "acct_cascade", Amount: 125, Currency: "USD"},
},
}
err := db
.Cascade("transactions:Transaction(accountId, id)")
.Save(ctx, onyx.TableAccount, acct)Cascade builder
Fluent builder that emits the cascade string.
rel := db
.CascadeBuilder()
.Graph("Transactions")
.GraphType("Transaction")
.TargetField("AccountId")
.SourceField("Id")
fmt.Println(rel.String()) // transactions:Transaction(accountId, id)Cascade string syntax
<field>:<RelatedTable>(<targetField>, <sourceField>) — field: property on the parent holding related rows; RelatedTable: table to upsert; targetField: FK on the related table; sourceField: parent field to copy.
Resolvers
Hydrate related data defined in your schema without extra round trips.
Fetch by id with resolver
Load a transaction and its account in one call.
tx, err := db.Transactions().Resolve("account").Find(ctx, "txn_123")Query with resolver
Filter base table and include related account data.
rows, err := db.Transactions()
.Where(onyx.Eq("status", "posted"))
.Resolve("account")
.List(ctx)Filter by resolver field
Filter using fields exposed by the resolver.
rows, err := db.Transactions()
.Where(onyx.Eq("account.name", "Primary"))
.Resolve("account")
.List(ctx)Bulk Save
Insert many records efficiently by passing a slice to Save.
txns := []onyx.Transaction{
{Id: "txn_batch_1", AccountId: "acct_batch", Amount: 1.99, Currency: "USD"},
{Id: "txn_batch_2", AccountId: "acct_batch", Amount: 12.50, Currency: "USD"},
{Id: "txn_batch_3", AccountId: "acct_batch", Amount: 45.00, Currency: "USD"},
{Id: "txn_batch_4", AccountId: "acct_batch", Amount: 7.25, Currency: "USD"},
}
err = db.Transactions()
.Save(ctx, txns)Query & Filter
Boolean filters, ranges, text contains, ordering, and limits.
txns, err := db.Transactions()
.Where(
onyx.Eq("status", "posted").
And(onyx.Gt("amount", 100)).
And(onyx.Gte("createdAt", "2025-01-01")).
And(onyx.Contains("merchant", "aws")),
)
.OrderBy(onyx.Desc("createdAt"))
.Limit(25)
.List(ctx)Defaults: if you omit Limit() and PageSize(), the API uses its server-side default page size (capped at 1000); responses include NextPage when more rows remain.
Query clauses
| Clause | Signature | What it does |
|---|---|---|
| Where | Where(condition) | Adds a boolean filter to the query. |
| And | Where(...).And(condition) | Chain additional AND conditions. |
| Or | Where(...).Or(condition) | Combine conditions with OR. |
| OrderBy | OrderBy(Asc/Desc("field")) | Sort the result set. |
| GroupBy | GroupBy(fields...) | Group results for aggregates. |
| Distinct | Distinct() | Return unique rows for selected fields. |
| Limit | Limit(n) | Cap number of records returned. |
| PageSize | PageSize(n) | Set page size for streaming pagination. |
| InPartition | InPartition(partition) | Filter to a single partition. |
| Page | Page(nextToken) | Fetch the next cursor page. |
Filters
| Helper | Signature | What it does |
|---|---|---|
| Eq | Eq("field", value) | Equals. |
| Neq | Neq("field", value) | Not equals. |
| Gt | Gt("field", value) | Greater than. |
| Gte | Gte("field", value) | Greater than or equal. |
| Lt | Lt("field", value) | Less than. |
| Lte | Lte("field", value) | Less than or equal. |
| Between | Between("field", low, high) | Inclusive range. |
| Contains | Contains("field", text) | Substring contains (case-sensitive). |
| ContainsIC | ContainsIC("field", text) | Substring contains (case-insensitive). |
| StartsWith | StartsWith("field", text) | Prefix match. |
| InOp | InOp("field", values) | Field in list of values. |
| NotIn | NotIn("field", values) | Field not in list of values. |
| Within | Within("field", subquery) | Field in subquery results. |
| IsNull | IsNull("field") | Field is null. |
| NotNull | NotNull("field") | Field is not null. |
| SearchWithOptions | SearchWithOptions(text, SearchOptions) | High-level lexical, semantic, or hybrid search. |
| Search | Search("query text", minScore...) | Legacy exhaustive lexical search with an optional native score threshold. |
Select Query
Pick specific columns to return from a table.
rows, err := db.Select("id", "accountId", "amount", "createdAt")
.From(onyx.TableTransaction)
.List(ctx)First or Null
When you expect a single row, use FirstOrNil (alias One).
first, err := db.Transactions()
.Where(onyx.Eq("id", "txn_123"))
.FirstOrNil(ctx)
one, err := db.Transactions()
.Where(onyx.Eq("id", "txn_123"))
.One(ctx)Inner Queries
Filter a table using sub-selects returned from another query.
records := db.Select("accountId")
.From(onyx.TableTransaction)
.Where(onyx.Gt("amount", 1000))
rows, err := db.Accounts()
.Where(onyx.Within("id", records))
.List(ctx)Update Query
Set partial updates for all rows matching a condition.
updated, err := db.Transactions()
.Where(onyx.Eq("status", "pending").And(onyx.Gt("amount", 100))).
.Set(map[string]any{"status": "posted"}).
.Update(ctx)Delete Query
Delete all rows that match a filter.
deletedCount, err := db.Transactions()
.Where(onyx.Eq("status", "archived")).
.Delete(ctx)Group By
Group results by one or more fields to segment metrics.
rows, err := db.Select("merchant", "currency")
.From(onyx.TableTransaction)
.Where(onyx.Eq("status", "posted"))
.GroupBy("merchant", "currency")
.List(ctx)Aggregations
Server-side rollups for dashboards and billing summaries.
rows, err := db.Select(onyx.Sum("amount"), "merchant")
.From(onyx.TableTransaction)
.Where(onyx.Eq("status", "posted"))
.List(ctx)Server-side aggregate helpers
| Function | Signature | What it does |
|---|---|---|
| sum | Sum("field") | Numeric sum of a column. |
| count | Count("field"|"*") | Row count. |
| avg | Avg("field") | Arithmetic mean. |
| min | Min("field") | Smallest value. |
| max | Max("field") | Largest value. |
| median | Median("field") | 50th percentile. |
| percentile | Percentile("field", p) | p-th percentile (0–100). |
| std | Std("field") | Sample standard deviation. |
| variance | Variance("field") | Sample variance. |
| upper | Upper("field") | Uppercase text for grouping/aggregation. |
| lower | Lower("field") | Lowercase text for grouping/aggregation. |
| format | Format("field", "pattern") | Apply Java-style date/number format before grouping. |
| substring | Substring("field", from, length) | Substring of text (0-based offset). |
| replace | Replace("field", pattern, repl) | Regex/substring replacement prior to grouping. |
Streaming Queries
Consume large result sets incrementally and react to live query responses.
iter, err := db.Transactions()
.Where(onyx.Eq("status", "posted"))
.PageSize(100)
.Stream(ctx)
defer iter.Close()
for iter.Next() {
msg := iter.Value()
fmt.Println(msg)
}
err = iter.Err()Lexical, Semantic & Hybrid Search
SearchWithOptions opts into the high-level SEARCH API. The zero-value SearchOptions selects hybrid mode, any-term lexical matching, no minimum score, and 1000 candidates. Search(text, minScore...) remains the legacy all-term MATCHES API. Semantic and hybrid modes require a server embedding provider; marking a table searchable does not configure one or backfill old rows.
Natural-language lexical search
SearchMatchAny ignores harmless extra question words. MinScore is normalized from 0 through 1, and MaxCandidates bounds admission work.
import sdk "github.com/OnyxDevTools/onyx-database-go/onyx"
minScore := 0.4
hits, err := db.Core().From("ActiveDocumentChunk").
SearchWithOptions(
"how do i calculate cost per horse",
sdk.SearchOptions{
Mode: sdk.SearchModeLexical,
Match: sdk.SearchMatchAny,
MinScore: &minScore,
MaxCandidates: 500,
},
).
List(ctx)Semantic search from ordinary text
The server embeds query text in the same model and vector space used when searchable rows are saved.
import sdk "github.com/OnyxDevTools/onyx-database-go/onyx"
related, err := db.Core().From("ActiveDocumentChunk").
SearchWithOptions(
"expense for each animal",
sdk.SearchOptions{Mode: sdk.SearchModeSemantic},
).
List(ctx)Hybrid search
Fuses lexical and semantic candidates. The zero-value SearchOptions selects canonical hybrid/any defaults.
import sdk "github.com/OnyxDevTools/onyx-database-go/onyx"
results, err := db.Core().From("ActiveDocumentChunk").
SearchWithOptions(
"how do i calculate cost per horse",
sdk.SearchOptions{},
).
And(sdk.Eq("isActive", true)).
Limit(50).
List(ctx)Search across eligible tables
Database-wide high-level search covers eligible unpartitioned searchable tables and returns result envelopes.
import sdk "github.com/OnyxDevTools/onyx-database-go/onyx"
acrossTables, err := db.Core().
SearchWithOptions(
"how do i calculate cost per horse",
sdk.SearchOptions{Mode: sdk.SearchModeHybrid},
).
Limit(50).
List(ctx)Legacy exhaustive lexical search
Existing Search calls keep their MATCHES wire shape and require every normalized term.
legacy, err := db.Core().From("ActiveDocumentChunk").
Search("cost per horse").
List(ctx)VectorSearchQuery controls
Use Text and/or Semantic; MinScore defaults to nil. The signature must use the table's active calibration.
import sdk "github.com/OnyxDevTools/onyx-database-go/onyx"
signature, err := sdk.NewSemanticVectorSignature(
73,
6,
[]int{1, 2},
[]int{4, 4},
[]int64{0x123456789abcdef0},
)
if err != nil { panic(err) }
radius, score, allTerms := 2, 0.2, false
query, err := sdk.NewVectorSearchQuery(sdk.VectorSearchQueryInput{
Text: "AWS spend",
Semantic: &signature,
MinScore: &score,
NearbyBucketRadius: &radius,
MaxCandidates: 256,
RequireAllTerms: &allTerms,
})
if err != nil { panic(err) }
hits, err := db.Core().From("Transaction").SearchVector(query).List(ctx)Bounded lexical candidates
Caps lexical admission work. SEARCH_CANDIDATES must remain the only root condition and cannot update or delete rows.
import sdk "github.com/OnyxDevTools/onyx-database-go/onyx"
bounded, err := sdk.NewVectorSearchQuery(sdk.VectorSearchQueryInput{
Text: "AWS spend",
MaxCandidates: 250,
})
if err != nil { panic(err) }
candidates, err := db.Core().From("Transaction").
ApproximateSearch(bounded).
List(ctx)Native HNSW candidates
Bounds nearest-neighbor work. Zero values default MaxCandidates to 1000, EFSearch to max(1000, MaxCandidates), and FormatVersion to 1. Add InPartition(...) for partitioned tables.
import sdk "github.com/OnyxDevTools/onyx-database-go/onyx"
minScore := 0.2
hnsw, err := sdk.NewHNSWSearchQuery(sdk.HNSWSearchQueryInput{
CalibrationID: 73,
Vector: embedding,
MaxCandidates: 256,
EFSearch: 1024,
MinScore: &minScore,
})
if err != nil { panic(err) }
nearest, err := db.Core().From("Transaction").HNSWCandidates(hnsw).List(ctx)Ordinary-index candidates
Use ApproximateCandidates as a normal Where condition. A scalar uses bounded EQUAL admission and a slice uses bounded IN admission; exactly one candidate condition may be combined with non-negated AND filters. MaxCandidates defaults to 1000.
import sdk "github.com/OnyxDevTools/onyx-database-go/onyx"
routed, err := db.Core().From("Transaction").
Where(sdk.ApproximateCandidates("merchant", []string{"AWS", "GCP"}, 200)).
And(sdk.Eq("status", "posted")).
List(ctx)Pagination
Page through ordered results with stable cursors (offset-free).
page1, err := db.Transactions()
.OrderBy(onyx.Asc("createdAt"))
.Limit(50)
.Page(ctx, "")
next := page1.NextPage
if next != "" {
page2, err := db.Transactions()
.OrderBy(onyx.Asc("createdAt"))
.Page(ctx, next)
fmt.Println(page2, err)
}Published Model Predictions (REST)
Call models published from Model Builder with the database API origin and database read credentials. This standalone HTTP example covers raw inputs and saved scripts; it does not add methods to the Go SDK. Replace the published model key, input fields, and saved script with your own. Script parameter values must be strings. Match outputs to returned inputs or records because sequence windows can reduce the prediction count.
package main
import (
"bytes"
"encoding/json"
"fmt"
"net/http"
"net/url"
"os"
"strings"
"time"
)
func predictRequest(suffix string, body any) (map[string]any, error) {
baseURL := strings.TrimRight(os.Getenv("ONYX_DATABASE_BASE_URL"), "/")
if baseURL == "" { baseURL = "https://api.onyx.dev" }
endpoint := baseURL + "/data/" + url.PathEscape(os.Getenv("ONYX_DATABASE_ID")) +
"/model-builder/published-model/" + url.PathEscape("churn-model") + "/predict" + suffix
payload, err := json.Marshal(body)
if err != nil { return nil, err }
req, err := http.NewRequest(http.MethodPost, endpoint, bytes.NewReader(payload))
if err != nil { return nil, err }
req.Header.Set("Content-Type", "application/json")
req.Header.Set("x-onyx-key", os.Getenv("ONYX_DATABASE_API_KEY"))
req.Header.Set("x-onyx-secret", os.Getenv("ONYX_DATABASE_API_SECRET"))
client := &http.Client{Timeout: 60 * time.Second}
res, err := client.Do(req)
if err != nil { return nil, err }
defer res.Body.Close()
if res.StatusCode < 200 || res.StatusCode >= 300 {
return nil, fmt.Errorf("prediction failed: %s", res.Status)
}
var result map[string]any
err = json.NewDecoder(res.Body).Decode(&result)
return result, err
}
func main() {
result, err := predictRequest("", map[string]any{
"inputs": []map[string]any{
{"accountAgeDays": 420, "usageScore": 0.87},
{"accountAgeDays": 90, "usageScore": 0.42},
},
})
if err != nil { panic(err) }
fmt.Println(result["records"])
scriptResult, err := predictRequest("/script", map[string]any{
"scriptId": "score-active-customers",
"scriptParameters": map[string]string{"segment": "enterprise", "limit": "50"},
})
if err != nil { panic(err) }
fmt.Println(scriptResult["predictions"])
}AI Chat
Use the AI endpoint to answer questions that reference your data.
Chat completions
Control model, messages, streaming/raw response options.
resp, err := db.Chat(ctx, onyx.AIChatCompletionRequest{
Model: "onyx",
Messages: []onyx.AIChatMessage{
{Role: "system", Content: "You are a finance assistant. Respond with 3 concise bullet points."},
{Role: "assistant", Content: "I summarize trends and call out anomalies each Friday."},
{Role: "user", Content: "Draft a status update for finance stakeholders."},
},
})
fmt.Println(resp, err)Streaming chat
Stream tokens as they arrive.
stream, err := db.ChatStream(ctx, onyx.AIChatCompletionRequest{
Model: "onyx",
Stream: true,
Messages: []onyx.AIChatMessage{{Role: "user", Content: "List the top 3 spend categories this week."}},
})
defer stream.Close()
for stream.Next() {
chunk := stream.Value()
fmt.Println(chunk)
}
err = stream.Err()Shorthand chat (string in, string out)
Quick one-shot: send a single user prompt and return the first message content.
resp, err := db.Chat(ctx, onyx.AIChatCompletionRequest{
Model: "onyx",
Messages: []onyx.AIChatMessage{
{Role: "user", Content: "Summarize yesterday's transactions in two bullets."},
},
})
summary := resp.Choices[0].Message.Content
fmt.Println(summary, err)List available models
Discover model IDs before picking one.
models, err := db.GetModels(ctx)
for _, m := range models.Data {
fmt.Println(m.ID)
}Get model details
Inspect a specific model's capabilities and limits.
model, err := db.GetModel(ctx, "onyx")
fmt.Println(model, err)Request script approval
Validate a mutation script before execution.
resp, err := db.RequestScriptApproval(ctx, onyx.AIScriptApprovalRequest{
Script: "db.Save({ id: 'acct_1', name: 'Checking' })",
})
fmt.Println(resp, err)Documents
Upload binary files with metadata, fetch with optional resizing, or delete stored documents.
Save a document
Stores metadata in the DB and writes bytes to the database’s _documents path.
payload := []byte("hello")
err := db.Documents().Save(ctx, onyx.Document{
DocumentId: "hello.txt",
Path: "/docs/hello.txt",
MimeType: "text/plain",
Content: payload,
})Get a document
Fetches by documentId; width/height resize images on the fly.
doc, err := db.Documents().Get(ctx, "hello.txt", nil)
fmt.Println(doc, err)Delete a document
Removes the file and its metadata.
err := db.Documents().Delete(ctx, "hello.txt")Secrets
Manage encrypted secrets stored per database; client calls never persist plaintext.
List secrets (metadata only)
Returns keys, purposes, and timestamps—no values.
secrets, err := db.OnyxSecrets().List(ctx)
fmt.Println(secrets, err)Fetch a secret value
Decrypts and returns the plaintext for a single key.
secret, err := db.OnyxSecrets().Get(ctx, "stripe_api_key")
fmt.Println(secret, err)Create or rotate a secret
Stores the value encrypted at rest; re-encrypts on each update.
err := db.OnyxSecrets().Set(ctx, onyx.OnyxSecret{
Key: "stripe_api_key",
Value: "sk_live_...",
Purpose: "Stripe server key",
})Delete a secret
Removes the record from the database.
err := db.OnyxSecrets().Delete(ctx, "stripe_api_key")Schema
Fetch, diff, validate, and publish schema revisions.
core := db.Core()
current, err := core.GetSchema(ctx, nil)
temp := onyx.Table{
Name: "TempTable",
Fields: []onyx.Field{
{Name: "id", Type: "String", Primary: true},
{Name: "name", Type: "String"},
},
}
schema := onyx.Schema{Tables: append(current.Tables, temp)}
err := core.ValidateSchema(ctx, schema)
err = core.PublishSchema(ctx, schema)