Lux Docs

Build on Lux without guessing.

Lux Cloud + OSS core

Product docs for the Lux runtime: tables, cache, vectors, realtime, time series, auth, HTTP, SDK, CLI, and self-hosting.

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

Install
bun i @luxdb/sdk

Project client

Use the project client for Lux Cloud, browser apps, auth, and serverless environments. Project methods return { data, error } results.

Project client
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.

Direct connection
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.

Redis commands
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

Queries
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

Mutations
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.

Typed rows
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.

Joins + similarity
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 row

Realtime

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.

KSUB
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.

Practical split
// 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

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

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.

Types
import type {
  KSubEvent,
  LuxError,
  LuxResult,
  TableRow,
  TSMRangeResult,
  TSRangeOptions,
  TSSample,
  VSearchResult,
} from "@luxdb/sdk";