Quickstart — first query in 5 minutes

Pick the path that matches your stack.

Already running MongoDB / Postgres / Redis / Neo4j / ClickHouse / an S3 client? You don't need an SDK — point your existing client at Relata's compat port and use your bearer token as the password. Full port table + 3-step quickstarts per protocol: Compatibility & Doors. This page is the SDK path.

Prerequisites

# Start the server (terminal 1) — Docker is the fastest path
docker run -d -p 9090:9090 --name relata ghcr.io/relatadb/relata:2.0.0
# or from source: cargo run -p relata-cli -- serve
 
# Check it's live (terminal 2)
curl http://127.0.0.1:9090/health

No token is needed for local dev — the server starts in unauthenticated mode. Set RELATA_BEARER_TOKEN before handling real data.


Pick your language. Each example below connects to a local Relata server, inserts a row, and queries it back.


Python

pip install relata-sdk
from relata import RelataClient
 
# 1. Connect (no token needed for local dev).
client = RelataClient("http://localhost:9090", purpose="analytics")
 
# 2. Insert a row.
client.query("INSERT INTO Person (_pk, name, email) VALUES ('p1', 'Alice', 'alice@example.com')")
 
# 3. Query it back.
result = client.query("SELECT * FROM Person LIMIT 5")
for row in result:
    print(row["name"], row["email"])
 
# 4. Search (BM25 + hybrid).
hits = client.search("alice", "Person", limit=5, highlight=True)
for hit in hits.hits:
    print(hit.score, hit.fields.get("name"))
 
# 5. Memory (agent cognitive verbs).
from relata import Memory
mem = Memory("http://localhost:9090", bearer_token="", purpose="agent")
mid = mem.add("Alice prefers dark mode")
results = mem.search("ui preferences", top_k=3)

Jupyter notebook

%load_ext relata.ipython
 
%%relata --purpose analytics
SELECT * FROM Person LIMIT 10

Results appear as a pandas DataFrame automatically.


TypeScript

npm install @zysec-ai/relata-sdk
import { RelataClient } from "@zysec-ai/relata-sdk";
 
// 1. Connect.
const client = new RelataClient({ baseUrl: "http://localhost:9090" });
 
// 2. Insert a row.
await client.query({ purpose: "analytics", sql: "INSERT INTO Person (_pk, name, email) VALUES ('p1', 'Alice', 'alice@example.com')" });
 
// 3. Query it back.
const result = await client.query({ purpose: "analytics", sql: "SELECT * FROM Person LIMIT 5" });
for (const row of result.data) {
  console.log(row.name, row.email);
}
 
// 4. Search with matching strategy.
const hits = await client.search({ query: "alice", type: "Person", limit: 5, matchingStrategy: "all" });
 
// 5. Memory.
await client.remember("Alice prefers dark mode", { purpose: "agent" });
const memories = await client.recall("ui preferences", { topK: 3 });

Go

go get github.com/relatadb/sdk-go/v2
package main
 
import (
    "context"
    "fmt"
    "time"
    "github.com/relatadb/sdk-go/v2/relata"
)
 
func main() {
    ctx := context.Background()
 
    // 1. Connect.
    client := relata.New("http://localhost:9090", &relata.ClientOptions{
        BearerToken:    "",
        DefaultPurpose: "analytics",
        Timeout:        30 * time.Second,
    })
 
    // 2. Insert a row.
    client.Query(ctx, "INSERT INTO Person (_pk, name, email) VALUES ('p1', 'Alice', 'alice@example.com')")
 
    // 3. Query it back.
    result, _ := client.Query(ctx, "SELECT * FROM Person LIMIT 5")
    for _, row := range result.Rows {
        fmt.Println(row["name"], row["email"])
    }
 
    // 4. Search with typo tolerance.
    hits, _ := client.Search(ctx, "alice", "Person",
        relata.WithSearchLimit(5),
        relata.WithMatchingStrategy("all"),
    )
 
    // 5. Memory.
    mem, _ := relata.NewMemory("http://localhost:9090", "agent", &relata.MemoryOptions{
        Timeout: 30 * time.Second,
    })
    mem.Add(ctx, "Alice prefers dark mode")
    results, _ := mem.Search(ctx, "ui preferences", relata.WithTopK(3))
    _ = results
    _ = hits
}

Parameterized queries

Use $1, $2, … placeholders to bind values server-side — no concatenation, no injection risk.

Python? placeholders are auto-rewritten to $1, $2, …

result = client.query_params(
    "SELECT * FROM Person WHERE age = $1 AND city = $2",
    [25, "Karachi"],
    purpose="analytics",
)
 
# ? form also works
result = client.query_params("SELECT * FROM T WHERE id = ?", [42])

TypeScript

const r = await relata.queryWithParams(
  "SELECT * FROM Person WHERE age = $1 AND city = $2",
  [25, "Karachi"],
  { purpose: "analytics" },
);

Go

result, err := client.QueryWithParams(ctx,
    "SELECT * FROM Person WHERE age = $1 AND city = $2",
    []any{25, "Karachi"},
    relata.WithPurpose("analytics"),
)

Text embedding via VectorClient

The TypeScript VectorClient exposes embed and embedBatch to call the server's /embed endpoint directly. The server uses its built-in CPU lexical embedder (128-dim) when RELATA_ACCEL_ENDPOINT is unset, or the GPU sidecar when configured.

import { createClient, VectorClient } from "@zysec-ai/relata-sdk";
 
const relata = createClient("http://localhost:9090", {
  bearerToken: process.env.RELATA_TOKEN,
});
const vectors = new VectorClient(relata);
 
// Single text
const { embedding, model, dim } = await vectors.embed("Alice Smith");
console.log(`dim=${dim} model=${model}`);
 
// Batch
const { embeddings, count } = await vectors.embedBatch(["Alice", "Bob"]);
console.log(`${count} embeddings, each dim=${embeddings[0].length}`);

What's next