npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@deltex/client

v1.4.2

Published

Official TypeScript/JavaScript client for Deltex — edge-native SQL database

Readme

@deltex/client

Official TypeScript/JavaScript client for Deltex — edge-native SQL database.

Install

npm install @deltex/client
# or
pnpm add @deltex/client

Quick start

import { createClient } from "@deltex/client";

// Auto-reads DELTEX_API_KEY from environment
const db = createClient();

type User = { id: number; name: string; email: string };

// Tagged template literals — primary API (injection-safe)
const users = await db<User[]>`SELECT id, name FROM users WHERE active = ${true}`;

// Single row
const user = await db.one<User>`SELECT * FROM users WHERE email = ${"[email protected]"}`;
if (!user) throw new Error("Not found");

// Mutations
const n = await db.exec`
  UPDATE users SET last_login = NOW()
  WHERE id = ${user.id}
`;
console.log(`${n} row updated`);

Postgres-compatible drivers (edge-native)

Deltex is HTTP-only at the edge, so there's no raw TCP Postgres port. Instead, @deltex/client/serverless exposes the familiar shapes of @neondatabase/serverless (neon()) and pg (Client / Pool) — each query is a single HTTPS round-trip, so it works from any edge or serverless runtime (Cloudflare Workers, Vercel Edge, Deno, Bun, Node ≥18) with no connection pool and no gateway.

neon() — Neon-compatible

import { neon } from "@deltex/client/serverless";

const sql = neon(process.env.DATABASE_URL);          // or neon({ apiKey })
const users = await sql`SELECT * FROM users WHERE id = ${id}`;
const r = await sql.query("SELECT * FROM users WHERE id = $1", [id]); // { rows, rowCount, fields, command }

The connection string's password is used as the Deltex API key: postgresql://user:[email protected]/db.

pg-compatible Client / Pool

import { Client, Pool } from "@deltex/client/serverless";

const client = new Client({ apiKey: process.env.DELTEX_API_KEY });
await client.connect();                 // no-op (connectionless)
const { rows } = await client.query("SELECT * FROM users WHERE id = $1", [id]);

// Atomic transaction (statements are committed together via /v1/transaction)
await client.transaction(async (tx) => {
  await tx.query("INSERT INTO orders (user_id, total) VALUES ($1, $2)", [id, 99]);
  await tx.query("UPDATE users SET order_count = order_count + 1 WHERE id = $1", [id]);
});

Drizzle ORM

import { drizzle } from "@deltex/client/drizzle";  // requires `drizzle-orm`
import { pgTable, integer, text } from "drizzle-orm/pg-core";
import { eq } from "drizzle-orm";

const users = pgTable("users", { id: integer("id").primaryKey(), name: text("name") });
const db = drizzle(process.env.DATABASE_URL);       // or drizzle({ apiKey })

const rows = await db.select().from(users).where(eq(users.id, 1));

Backed by drizzle-orm/pg-proxy — fully edge-native, no TCP.

API

createClient(options?)

// Node/Deno/Bun — reads DELTEX_API_KEY and DELTEX_ENDPOINT from env
const db = createClient();

// Cloudflare Workers, edge runtimes (no process.env)
const db = createClient({ apiKey: env.DELTEX_API_KEY });

// Custom endpoint + write mode
const db = createClient({
  apiKey: env.DELTEX_API_KEY,
  endpoint: "https://db.deltex.dev",
  writeMode: "sync", // "sync" (default, durable) | "edge" | "async"
});

| Option | Type | Default | Description | |--------|------|---------|-------------| | apiKey | string | DELTEX_API_KEY env | API key from Deltex dashboard | | endpoint | string | DELTEX_ENDPOINT env or https://db.deltex.dev | Engine URL | | writeMode | "sync" \| "edge" \| "async" | "sync" | Write durability mode | | timeoutMs | number | 30000 | Request timeout | | fetch | typeof fetch | globalThis.fetch | Custom fetch (Node < 18) |

Tagged template literal — db\sql``

Primary API. SQL is split at interpolation boundaries — values are never concatenated as raw strings.

const id = 42;
const users = await db<User[]>`SELECT * FROM users WHERE id = ${id}`;
//                                                                ^^^
//                              Safely formatted as: ... WHERE id = 42

db.one\sql`` — Single row

Returns the first row or undefined.

const user = await db.one<User>`SELECT * FROM users WHERE id = ${id}`;
// user: User | undefined

db.exec\sql`` — Mutations

Returns rows affected count.

const n = await db.exec`DELETE FROM sessions WHERE expires_at < NOW()`;
// n: number

db.raw\sql`` — Full result envelope

const result = await db.raw`SELECT * FROM users`;
// result.rows: Row[]
// result.columns: string[]
// result.rowsAffected: number
// result.executionMs: number | null

db.transaction(fn) — Transactions

Runs BEGIN → your function → COMMIT on success, ROLLBACK on error.

const order = await db.transaction(async (tx) => {
  const [account] = await tx<Account[]>`
    SELECT balance FROM accounts WHERE id = ${userId} FOR UPDATE
  `;

  if (account.balance < amount) throw new Error("Insufficient funds");

  await tx`UPDATE accounts SET balance = balance - ${amount} WHERE id = ${userId}`;
  await tx`INSERT INTO transactions (user_id, amount) VALUES (${userId}, ${amount})`;

  const [created] = await tx<Transaction[]>`
    SELECT * FROM transactions ORDER BY id DESC LIMIT 1
  `;
  return created;
});

db.batch(statements) — Fastest bulk write

Applies an array of SQL statements in one round-trip, committed atomically. Returns the total rows affected.

const n = await db.batch([
  "INSERT INTO products (name, price) VALUES ('Apple', 0.99)",
  "INSERT INTO products (name, price) VALUES ('Banana', 0.59)",
  "UPDATE inventory SET stock = stock - 1 WHERE sku = 'A1'",
]);
// n === 3

Looping execute makes one durable commit per statement. batch() (and a single multi-row INSERT) coalesce them into one commit — O(1) instead of O(N) — so it's far faster for bulk writes. Reach for it whenever you're writing many rows at once.

batch() takes raw SQL strings (no parameter binding). For untrusted values, build statements safely or use transaction with tagged templates — both commit in one round-trip.

db.withWriteMode(mode) — Per-operation write mode

const syncDb = db.withWriteMode("sync");  // Wait for the durable write
const fastDb = db.withWriteMode("async"); // Fire and forget

await syncDb.exec`INSERT INTO audit_log (event) VALUES (${"payment"})`;

db.query(sql, params?) — Positional parameters

For dynamic SQL generation where tagged templates aren't convenient:

const cols = ["id", "name", "email"].join(", ");
const users = await db.query<User>(`SELECT ${cols} FROM users WHERE id = $1`, [42]);

Write Modes

| Mode | Durability | Use When | |------|------------|----------| | sync (default) | Durable commit | Everything by default; never loses an acked write | | edge | CAS-protected async, eventual durability | Caches, sessions, idempotent upserts — not loss-critical data | | async | Fire-and-forget | High-volume events, telemetry |

Error Handling

import { DeltexError } from "@deltex/client";

try {
  await db`SELECT * FROM nonexistent_table`;
} catch (err) {
  if (err instanceof DeltexError) {
    console.error(err.message);        // "Table does not exist"
    console.error(err.engineMessage);  // Raw engine error
    console.error(err.status);         // HTTP status (400)
    console.error(err.sql);            // The SQL that failed
  }
}

Examples

Next.js App Router

// lib/db.ts
import { createClient } from "@deltex/client";
export const db = createClient(); // reads DELTEX_API_KEY from env

// app/users/[id]/page.tsx
import { db } from "@/lib/db";
export default async function UserPage({ params }: { params: { id: string } }) {
  const user = await db.one`SELECT * FROM users WHERE id = ${Number(params.id)}`;
  if (!user) notFound();
  return <div>{user.name}</div>;
}

Cloudflare Workers

import { createClient } from "@deltex/client";

export default {
  async fetch(req: Request, env: Env) {
    const db = createClient({ apiKey: env.DELTEX_API_KEY });
    const products = await db`SELECT id, name, price FROM products LIMIT 20`;
    return Response.json(products);
  },
};

Batch insert

For untrusted values, use a transaction with tagged templates — writes are collected and committed in one round-trip, safely parameterized:

const items = [{ name: "Apple", price: 0.99 }, { name: "Banana", price: 0.59 }];

await db.transaction(async (tx) => {
  for (const item of items) {
    await tx`INSERT INTO products (name, price) VALUES (${item.name}, ${item.price})`;
  }
});

If you already hold an array of trusted SQL strings, db.batch(statements) does the same in one call.

License

MIT