SDK
Official TypeScript client for Lux. Use the project client for browser/server apps, or the direct client when you want Redis-compatible TCP access.
Install
bun i @luxdb/sdkProject client
Use the project client for Lux Cloud, browser apps, auth, and serverless environments.
Project methods return { data, error } results.
import { createBrowserClient, createClient, createServerClient } from "@luxdb/sdk";
// Browser app client. Use your project's publishable key.
const lux = createBrowserClient(
"https://api.luxdb.dev/v1/my-project",
"lux_pub_..."
);
const { data: session, error } = await lux.auth.signInWithPassword({
email: "user@example.com",
password: "correct horse battery staple",
});
const { data: rows } = await lux
.table<{ id: number; email: string; age: number }>("users")
.select()
.gt("age", 25)
.order("age", { ascending: false })
.limit(10);
// Trusted server client. Use a secret key only on servers.
const admin = createClient("https://api.luxdb.dev/v1/my-project", "lux_sec_...");
// SSR client. Sessions are persisted through your framework's cookie methods.
const ssr = createServerClient("https://api.luxdb.dev/v1/my-project", "lux_pub_...", {
cookies,
});Direct client
Use the direct client from trusted server code when you want the Redis-compatible protocol, pipelining, or raw command access.
import Lux, { createClient } from "@luxdb/sdk";
const lux = new Lux("lux://127.0.0.1:6379");
const local = new Lux({
host: "localhost",
port: 6379,
password: "optional-password",
});
const client = createClient("lux://localhost:6379");Because the client extends ioredis, standard Redis commands still work directly.
await lux.set("key", "value");
await lux.get("key");
await lux.hset("hash", "field", "value");
await lux.lpush("list", "item1", "item2");Tables
The main SDK surface is lux.table(...). Queries and mutations return { data, error } so application code can handle success and failure
explicitly.
Query rows
const users = lux.table("users");
const { data: rows, error } = await users
.select()
.gte("age", 18)
.order("age", { ascending: false })
.limit(20);
if (error) throw error;
console.log(rows);Insert, update, delete
const { data: inserted, error: insertError } = await users.insert({
name: "Alice",
email: "alice@example.com",
age: 30,
});
const { data: updated, error: updateError } = await users
.update({ age: 31 })
.eq("email", "alice@example.com");
const { data: deleted, error: deleteError } = await users
.delete()
.eq("email", "alice@example.com");Typed rows
Pass a generic type parameter when you want a typed row shape. If you supply a parser or
safe parser, the SDK validates rows at runtime. That makes it compatible with schema objects
that expose parse or safeParse, including Zod.
type UserRow = {
id: number;
name: string;
email: string;
age: number;
};
const users = lux.table<UserRow>("users");
const { data: user, error } = await users
.select()
.eq("id", 42)
.single();Joins and similarity
Joins and table/vector composition are available on the direct client today.
const { data: joined } = await direct
.table("posts")
.select()
.join("users", "u", "posts.author_id", "u.id")
.eq("u.name", "alice")
.run();
const { data: matches } = await direct
.table("documents")
.similar("embedding", [0.12, 0.88, 0.44], { k: 5 })
.run();
// similarity results include _similarity on each rowRealtime
Use direct KSUB when you need raw keyspace pattern subscriptions. Project-client realtime over the Cloud gateway is intentionally documented separately as it stabilizes.
Low-level KSUB
KSUB listens for mutations on keys matching one or more glob patterns.
const sub = lux.ksub(["user:*", "session:*"], (event) => {
console.log(event.pattern);
console.log(event.key);
console.log(event.operation);
});
sub.unsubscribe();Examples
A practical split is: use project clients for app data and auth, use direct commands for KV/cache work, and use native primitives like vectors and time series when the app needs them.
// cache
await lux.set("session:42", JSON.stringify(session));
// relational data
const { data: messages } = await lux
.table("messages")
.select()
.eq("channel_id", "general")
.order("id", { ascending: false })
.limit(50);
// vectors
const { data: matches } = await lux.vectorSearch({
vector: [0.1, 0.2, 0.3],
k: 10,
});Vectors
await lux.vset("docs:1", [0.1, 0.2, 0.3], {
metadata: { row_id: 1, title: "Intro" },
});
const vector = await lux.vget("docs:1");
const results = await lux.vsearch([0.1, 0.2, 0.3], {
k: 10,
meta: true,
});
const count = await lux.vcard();Time Series
await lux.tsadd("temperature", "*", 72.5, {
labels: { sensor: "living-room", unit: "fahrenheit" },
});
const sample = await lux.tsget("temperature");
const samples = await lux.tsrange("temperature", "-", "+");
const series = await lux.tsmrange("-", "+", "sensor=living-room");
const info = await lux.tsinfo("temperature");TypeScript Types
The SDK exports types for tables, KSUB events, vectors, time series, auth, and result handling.
import type {
KSubEvent,
LuxError,
LuxResult,
TableRow,
TSMRangeResult,
TSRangeOptions,
TSSample,
VSearchResult,
} from "@luxdb/sdk";