TypeScript / JavaScript SDK
TypeScript / JavaScript SDK
Package: @heliosdb/client (REST/Realtime, Supabase-compatible) or pg / postgres / node-postgres (direct PG wire)
Repo: heliosdb-sdks
Compatible with: all HeliosDB editions (Nano, Lite, Full)
UVP
Two valid paths from Node.js / TypeScript into HeliosDB Nano: the @heliosdb/client package for a Supabase-compatible fluent API (db.from('table').select()) backed by REST + WebSocket, or the standard pg / postgres / Drizzle / Prisma stack for direct PostgreSQL-wire access. Both work against the same data; pick by use case. No proprietary driver required. This page shows hands-on snippets for each path — connect, CRUD, vector search — and links to a full end-to-end app tutorial.
Path A — REST + Realtime (@heliosdb/client)
Idiomatic for Next.js / Astro / SvelteKit apps that already know Supabase.
Install
npm install @heliosdb/clientConnect
import { createClient } from "@heliosdb/client";
const db = createClient( "http://localhost:8080", "anon-key" // any string before login);Auth
// Signupconst { data: signupData } = await db.auth.signUp({ email: "alice@example.com", password: "s3cret",});
// Login (returns a session attached to the client)const { data: { session } } = await db.auth.signInWithPassword({ email: "alice@example.com", password: "s3cret",});console.log("access_token:", session.access_token);CRUD
// Insertconst { data: post } = await db .from("posts") .insert({ title: "Hello Nano", body: "First post" }) .select() .single();
// Read with filter chainconst { data: recent } = await db .from("posts") .select("id, title, body, created_at") .ilike("title", "%nano%") .gte("created_at", "2026-04-01") .order("created_at", { ascending: false }) .range(0, 9); // first 10 rows
// Updateawait db.from("posts") .update({ body: "edited" }) .eq("id", post.id);
// Deleteawait db.from("posts").delete().eq("id", post.id);The 20 PostgREST filter operators (eq, gt, gte, lt, lte, like, ilike, in, is, cs, cd, ov, fts, plfts, phfts, wfts, not, or, and, neq) all map to chain methods.
Vector Search
const results = await db.vectorSearch("docs", [0.1, 0.2, 0.3, /* ...384 dims... */], { topK: 10, metric: "cosine", // "cosine" | "l2" | "ip" filter: { category: "tech" },});
for (const hit of results) { console.log(hit.id, hit.score, hit.row.title);}Realtime
const channel = db .channel("posts-changes") .on( "postgres_changes", { event: "*", schema: "public", table: "posts" }, (payload) => { console.log(payload.eventType, payload.new ?? payload.old); } ) .subscribe();
// channel.unsubscribe() to stopOpens ws://localhost:8080/realtime/v1/websocket and emits the same event shape Supabase does. RLS applies on the WebSocket too — clients see only rows their JWT can read.
Path B — Direct PG Wire (postgres / pg / Drizzle / Prisma)
Idiomatic for backend services with heavy SQL, transactions, or ORM usage.
postgres (porsager/postgres)
npm install postgresimport postgres from "postgres";
const sql = postgres("postgresql://postgres:s3cret@127.0.0.1:5432/postgres");
// Tagged-template parameters (auto-escaped)const users = await sql`SELECT id, name FROM users WHERE age > ${18}`;
await sql` INSERT INTO users (name, age) VALUES (${"Alice"}, ${30})`;
await sql.end();pg (node-postgres)
npm install pgimport { Pool } from "pg";
const pool = new Pool({ connectionString: "postgresql://postgres:s3cret@127.0.0.1:5432/postgres",});
const { rows } = await pool.query( "SELECT id, title FROM posts WHERE author = $1", ["alice@example.com"],);console.log(rows);
await pool.end();Drizzle ORM
import { drizzle } from "drizzle-orm/node-postgres";import { Pool } from "pg";import { pgTable, serial, text, timestamp } from "drizzle-orm/pg-core";
const posts = pgTable("posts", { id: serial("id").primaryKey(), title: text("title").notNull(), body: text("body"), createdAt: timestamp("created_at").defaultNow(),});
const pool = new Pool({ connectionString: "postgresql://postgres:s3cret@127.0.0.1:5432/postgres" });const db = drizzle(pool);
const [row] = await db.insert(posts).values({ title: "Hi", body: "..." }).returning();const all = await db.select().from(posts).limit(50);Drizzle (and Prisma) work without modification — the v3.14.5–v3.14.10 patches in CHANGELOG.md address every Drizzle edge case (quoted identifiers, mixed-qualifier GROUP BY, parameterized LIMIT/OFFSET, timestamp wire format).
Vector Search via PG Wire
function vecLit(v: number[]): string { return "[" + v.map(x => x.toFixed(6)).join(",") + "]";}
const qVec = [/* 384 dims */];
const { rows } = await pool.query( `SELECT id, title, embedding <=> $1::vector AS distance FROM docs ORDER BY distance LIMIT $2`, [vecLit(qVec), 5],);The $1::vector cast tells the planner to coerce the text literal into a VECTOR(384) value.
When to Pick Which
| Need | Use |
|---|---|
| Frontend / serverless function | Path A (@heliosdb/client) |
| Realtime subscriptions | Path A |
| Drop-in Supabase migration | Path A |
| Drizzle / Prisma / TypeORM | Path B (pg / postgres) |
Bulk import (COPY FROM) | Path B |
| Heavy transactional workload | Path B |
| Multi-tenant RLS via JWT | Either — both honor JWT claims |
You can mix both in one repo — REST/Realtime for the API edge, Drizzle for batch jobs and migrations.
Next Steps
- NODEJS_BAAS_APP — full TypeScript app, REST + Realtime + RLS.
- BAAS_REST_API_TUTORIAL — REST endpoints at the curl level.
- Python SDK — same surface in Python.
- Go SDK — Go via PG wire.