Node.js Client Library

The Node.js client provides a TypeScript-first API for Geode with QUIC + TLS 1.3 (default) or gRPC transport, pooling, query builders, and prepared statements.

Installation

npm install @geodedb/client

Quick Start

import { createClient } from '@geodedb/client';

const client = await createClient('quic://localhost:3141');

const rows = await client.queryAll(
  'MATCH (p:Person) RETURN p.name AS name, p.age AS age'
);

for (const row of rows) {
  console.log(`${row.name}: ${row.age}`);
}

await client.close();

DSN Format

Note: See the official DSN specification for complete details.

quic://[username:password@]host[:port][?options]   # QUIC transport (default port: 3141)
grpc://[username:password@]host[:port][?options]   # gRPC transport (default port: 50051)
host:port                                          # Scheme-less (defaults to QUIC)

Supported options: page_size, hello_name, hello_ver, conformance, username/user, password/pass, ca, cert, key, insecure_tls_skip_verify, server_name, connect_timeout, request_timeout, tls (gRPC only).

Environment defaults: GEODE_HOST, GEODE_PORT, GEODE_TRANSPORT, GEODE_TLS_CA, GEODE_USERNAME, GEODE_PASSWORD.

Pooling

Pooling is enabled by default. Configure it via ClientOptions:

const client = await createClient('quic://localhost:3141', {
  pooling: true,
  pool: {
    min: 2,
    max: 10,
    acquireTimeout: 30000,
    idleTimeout: 60000,
  },
});

Disable pooling for a single connection:

const client = await createClient('quic://localhost:3141', { pooling: false });

Queries

const result = await client.query('MATCH (n) RETURN n');
for await (const row of result) {
  const node = row.get('n')?.asNode;
  console.log(node);
}

const rows = await client.queryAll('MATCH (n) RETURN n.name AS name');
const first = await client.queryFirst('MATCH (n) RETURN n LIMIT 1');
const count = await client.queryScalar<number>('MATCH (n) RETURN count(n) AS cnt', 'cnt');

Streaming Queries

query() returns an async iterator for streaming large result sets:

const result = await client.query('MATCH (p:Person) RETURN p.name AS name');
for await (const row of result) {
  console.log(row.get('name')?.asString);
}

Parameters and Cancellation

const controller = new AbortController();

const rows = await client.queryAll(
  'MATCH (p:Person) WHERE p.age > $minAge RETURN p.name AS name',
  { params: { minAge: 21 }, signal: controller.signal, pageSize: 1000 }
);

Transactions

await client.withTransaction(async (tx) => {
  await tx.exec("CREATE (:Person {name: 'Alice'})");
  await tx.exec("CREATE (:Person {name: 'Bob'})");
});

Manual transaction control with savepoints:

const conn = await client.getConnection();
const tx = await conn.begin();
try {
  await tx.exec("CREATE (p:Person {name: 'Alice'})");
  await tx.savepoint('before_update');
  await tx.exec("MATCH (p:Person {name: 'Alice'}) SET p.age = 30");
  await tx.rollbackTo('before_update');
  await tx.commit();
} catch (err) {
  await tx.rollback();
  throw err;
} finally {
  await client.releaseConnection(conn);
}

Prepared Statements

const stmt = await client.prepare('MATCH (p:Person {name: $name}) RETURN p');

const rows = await stmt.executeAll({ name: 'Alice' });
stmt.close();

Query Builder

import { query } from '@geodedb/client';

const { query: gql, params } = query()
  .match('(p:Person)')
  .return('p.name AS name')
  .build();

const rows = await client.queryAll(gql, { params });

Explain and Profile

import { explain, profile } from '@geodedb/client';

await client.withConnection(async (conn) => {
  const plan = await explain(conn, 'MATCH (p:Person) RETURN p');
  const prof = await profile(conn, 'MATCH (p:Person) RETURN p');
  console.log(plan, prof);
});

Authentication Helpers

import { createAuthClient } from '@geodedb/client';

await client.withConnection(async (conn) => {
  const auth = createAuthClient(conn);
  const user = await auth.currentUser();
  console.log(user);
});

Connection Management

await client.withConnection(async (conn) => {
  const rows = await conn.queryAll('MATCH (n) RETURN n LIMIT 10');
  console.log(rows);
});

Error Handling

import { isGeodeError, DriverError } from '@geodedb/client';

try {
  await client.exec('INVALID QUERY');
} catch (err) {
  if (isGeodeError(err)) {
    if (err instanceof DriverError && err.isRetryable) {
      // Retry logic
    }
  }
  throw err;
}

Type Mapping

  • queryAll returns plain JavaScript objects.
  • query returns Row objects (Map<string, GQLValue>).
  • Use row.get('field') for typed access, or result.toObjects() to convert.

Repository