---
title: "TypeScript / JavaScript SDK"
---

# TypeScript / JavaScript SDK

**Package:** `@heliosdb/client` (REST/Realtime, Supabase-compatible) **or** `pg` / `postgres` / `node-postgres` (direct PG wire)
**Repo:** [heliosdb-sdks](https://github.com/HeliosDatabase/HeliosDB-SDKs)
**Compatible with:** Path B (PostgreSQL wire) works with every HeliosDB edition (Nano, Lite, Full); Path A targets Nano's REST, auth and realtime surface

---

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

:::caution[Known issue]
The `/rest/v1` table routes that Path A uses are a known issue in the current release
(see [Known Limitations](https://www.heliosdb.com/docs/nano/reference/compatibility/known-limitations/#planned)).
Use Path B (the PostgreSQL wire protocol) for table access until it is fixed.
:::

### Install

```bash
# @heliosdb/client is not published on npm; build it from source
git clone https://github.com/HeliosDatabase/HeliosDB-SDKs.git
(cd HeliosDB-SDKs/sdks/typescript && npm install && npm run build)
npm install ./HeliosDB-SDKs/sdks/typescript
```

### Connect

```ts
import { createClient } from "@heliosdb/client";

const db = createClient(
    "http://localhost:8080",
    "anon-key"        // any string before login
);
```

### Auth

```ts
// Signup
const { 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

```ts
// Insert
const { data: post } = await db
    .from("posts")
    .insert({ title: "Hello Nano", body: "First post" })
    .select()
    .single();

// Read with filter chain
const { 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

// Update
await db.from("posts")
    .update({ body: "edited" })
    .eq("id", post.id);

// Delete
await db.from("posts").delete().eq("id", post.id);
```

Nano's REST filters support `eq`, `neq`, `gt`, `gte`, `lt`, `lte`, `like`, `ilike`, `is` and `in`, with `not.` negation; `cs`, `cd`, `ov`, full-text and `or`/`and` filters are planned. The client's chain methods for the planned operators fail against the current release.

### Vector Search

```ts
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

```ts
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 stop
```

Opens `ws://localhost:8080/realtime/v1/websocket` and emits the same event shape Supabase does. Known issue: realtime events are not delivered in the current release; tracked by the Nano team. Realtime subscriptions are not filtered by row-level security: a subscriber receives every change on the tables it subscribes to. Secured realtime is planned.

---

## Path B — Direct PG Wire (`postgres` / `pg` / Drizzle / Prisma)

Idiomatic for backend services with heavy SQL, transactions, or ORM usage.

### `postgres` (porsager/postgres)

```bash
npm install postgres
```

```ts
import 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)

```bash
npm install pg
```

```ts
import { 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

```ts
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 fixes recorded in the [changelog](https://www.heliosdb.com/docs/nano/releases/changelog/) address every Drizzle edge case (quoted identifiers, mixed-qualifier GROUP BY, parameterized LIMIT/OFFSET, timestamp wire format).

### Vector Search via PG Wire

```ts
// Numbers only, so the literal cannot carry SQL.
function vecLit(v: number[]): string {
    return "'[" + v.map(x => Number(x).toFixed(6)).join(",") + "]'";
}

const qVec = [/* 384 dims */];

const { rows } = await pool.query(
    `SELECT id, title, embedding <=> ${vecLit(qVec)}::vector AS distance
     FROM docs
     ORDER BY distance
     LIMIT $1`,
    [5],
);
```

The query vector is inlined as a `'[...]'::vector` literal. In the current release a `::vector`
cast on a bound parameter (`$1::vector`) fails; only inline literals work
([#33](https://github.com/HeliosDatabase/HeliosDB-Nano/issues/33), see
[Known Limitations](https://www.heliosdb.com/docs/nano/reference/compatibility/known-limitations/)).

---

## When to Pick Which

| Need | Use |
|------|-----|
| Frontend / serverless function | Path A (`@heliosdb/client`) |
| Realtime subscriptions | Known issue (tracked) |
| 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 | Neither in the stock server: enforce per-user access in your service layer (SQL `CREATE POLICY` and RLS for REST and wire clients are planned) |

You can mix both in one repo — REST/Realtime for the API edge, Drizzle for batch jobs and migrations.

---

## Next Steps

- [NODEJS_BAAS_APP](https://www.heliosdb.com/docs/nano/guides/tutorials/sdk/nodejs_baas_app/) — full TypeScript app, REST + Realtime.
- [BAAS_REST_API_TUTORIAL](https://www.heliosdb.com/docs/nano/guides/tutorials/baas_rest_api_tutorial/) — REST endpoints at the curl level.
- [Python SDK](https://www.heliosdb.com/docs/nano/api/python-sdk/) — same surface in Python.
- [Go SDK](https://www.heliosdb.com/docs/nano/api/go-sdk/) — Go via PG wire.
