Skip to content

Getting Started

This guide walks you through installing db2-node, connecting to a DB2 database, and running your first queries.

Prerequisites

  • Node.js 18 or later
  • DB2 instance (local or remote) — see Development Setup for Docker instructions

Installation

bash
npm install db2-node

db2-node ships prebuilt native binaries for:

  • Linux: x64 glibc, x64 musl, arm64 glibc, arm64 musl
  • macOS: x64, arm64 (Apple Silicon)
  • Windows: x64, arm64

No compiler toolchain needed for supported platforms.

Connecting to DB2

typescript
import { Client } from 'db2-node';

const client = new Client({
  host: 'localhost',
  port: 50000,
  database: 'MYDB',
  user: 'db2inst1',
  password: 'password',
});

await client.connect();

Connection Options

OptionTypeDefaultDescription
hoststringDB2 server hostname
portnumber50000DB2 server port
databasestringDatabase name
userstringUsername
passwordstringPassword
sslbooleanfalseEnable TLS/SSL
rejectUnauthorizedbooleantrueVerify server certificate
sslClientHostnameValidationstring'Basic'IBM-compatible hostname validation mode: 'Basic' or 'OFF'
caCertstringPath to CA certificate PEM file
connectTimeoutnumber30000Connection timeout in ms (TCP + TLS)
queryTimeoutnumber0Query timeout in ms (0 = no timeout)
frameDrainTimeoutnumber25DRDA reply frame drain timeout in ms
currentSchemastringDefault schema
fetchSizenumber100Rows per fetch batch

Running Queries

Simple Queries

typescript
const result = await client.query('SELECT * FROM employees');
console.log(result.rows);    // Array of row objects
console.log(result.rowCount); // Number of rows
console.log(result.columns);  // Column metadata

See Data Type Support for the Db2 for z/OS built-in type mapping, including BLOB, CLOB, DBCLOB, XML, ROWID, graphic strings, binary strings, and datetime values.

Parameterized Queries

Always use parameterized queries to prevent SQL injection:

typescript
const result = await client.query(
  'SELECT name, salary FROM employees WHERE dept_id = ? AND active = ?',
  [1, true]
);

INSERT / UPDATE / DELETE

typescript
const result = await client.query(
  'INSERT INTO employees (name, dept_id) VALUES (?, ?)',
  ['Alice', 1]
);
console.log(result.rowCount); // 1

Prepared Statements

For queries executed multiple times with different parameters:

typescript
const stmt = await client.prepare(
  'INSERT INTO employees (name, dept_id) VALUES (?, ?)'
);

await stmt.execute(['Alice', 1]);
await stmt.execute(['Bob', 2]);
await stmt.execute(['Carol', 1]);

// Batch insert (single round-trip)
await stmt.executeBatch([
  ['Dave', 3],
  ['Eve', 1],
]);

await stmt.close(); // always close when done

Transactions

typescript
const tx = await client.beginTransaction();

try {
  await tx.query('UPDATE accounts SET balance = balance - 100 WHERE id = ?', [1]);
  await tx.query('UPDATE accounts SET balance = balance + 100 WHERE id = ?', [2]);
  await tx.commit();
} catch (e) {
  await tx.rollback();
  throw e;
}

Transactions also support prepared statements via tx.prepare().

Connection Pool

For applications with concurrent database access, Pool supports the modern config-object API and the common ibm_db pool shape:

typescript
import { Pool } from 'db2-node';

const pool = new Pool({
  host: 'localhost',
  port: 50000,
  database: 'MYDB',
  user: 'db2inst1',
  password: 'password',
  maxConnections: 20,
});

// Pool manages connections automatically
const result = await pool.query('SELECT COUNT(*) AS cnt FROM employees');

// Or acquire a connection for multiple operations
const client = await pool.acquire();
try {
  // ... use client ...
} finally {
  await pool.release(client);
}

await pool.close();

CommonJS callers migrating from ibm_db can create a pool without connection config and open databases by connection string:

javascript
const ibmdb = require('db2-node');

const connStr = 'DATABASE=MYDB;HOSTNAME=localhost;PORT=50000;PROTOCOL=TCPIP;UID=db2inst1;PWD=password';
const pool = new ibmdb.Pool();

const db = await pool.open(connStr);
const rows = await db.query('SELECT COUNT(*) AS cnt FROM employees');

await db.close();
await pool.close();

Pool Options

All connection options above, plus:

OptionTypeDefaultDescription
minConnectionsnumber0Minimum idle connections to maintain
maxConnectionsnumber10Maximum total connections
idleTimeoutnumber600Close idle connections after this many seconds (10 min)
maxLifetimenumber3600Recycle connections after this many seconds (1 hour)
healthCheckIntervalnumber30Reuse an idle connection without a health-check round trip for this many seconds

TLS / SSL

typescript
// Skip certificate verification (development/testing)
const client = new Client({
  host: 'localhost',
  port: 50001,
  database: 'testdb',
  user: 'db2inst1',
  password: 'secret',
  ssl: true,
  rejectUnauthorized: false,
});

// Verify with custom CA certificate (production)
const client = new Client({
  host: 'db2.example.com',
  port: 50001,
  database: 'PRODDB',
  user: 'app_user',
  password: 'secret',
  ssl: true,
  caCert: '/path/to/ca-cert.pem',
});

// IBM CLI-compatible SSLServerCertificate behavior for DB2 certs without SANs
const client = new Client({
  host: 'db2-vip.example.com',
  port: 50001,
  database: 'PRODDB',
  user: 'app_user',
  password: 'secret',
  ssl: true,
  rejectUnauthorized: true,
  caCert: '/path/to/server-or-ca-cert.pem',
  sslClientHostnameValidation: 'OFF',
});

When rejectUnauthorized is true (the default), system trust store certificates are loaded automatically. Custom CA certificates from caCert are added on top. IBM-style connection strings can also use SSLServerCertificate=/path/to/cert.pem, which maps to caCert.

Hostname validation is enabled by default (sslClientHostnameValidation: 'Basic'). For IBM ibm_db connection string compatibility, SSLServerCertificate=/path/to/cert.pem defaults hostname validation to OFF unless SSLClientHostnameValidation=Basic is supplied explicitly. Object-style caCert config remains strict by default. Use sslClientHostnameValidation: 'OFF' only when the DB2 server certificate is trusted but does not contain a matching DNS/IP subjectAltName. That mode verifies the certificate chain and skips only the hostname/SAN check.

Db2 z/OS LOB Production Modes

Db2 for z/OS can continue sending external LOB data (EXTDTA) after an application has materialized the requested rows. The driver keeps pooled connections safe by verifying cleanup before reuse.

Default mode

Run normally with no z/OS LOB environment variables:

bash
node app.js

This is the recommended default. If a z/OS LOB query cannot be proven clean after materialization, the driver disconnects that socket and warm-replaces it in the pool. This prevents stale EXTDTA from corrupting the next query and is the fastest mode for large CLOB workloads where preserving the exact same server session is not required.

CLOB-like LIKE and NOT LIKE predicate scans that return aggregate or scalar results use a large statement package EXCSQLSTT path by default on Db2 for z/OS. Set DB2_ZOS_LIKE_PREDICATE_EXCSQLSTT=0 only while diagnosing package-specific behavior.

Errors returned through the JavaScript wrapper APIs include sqlstate, sqlcode, and retryable fields when the driver can infer them from the DB2 error. Stale z/OS cursor or statement state (SQLCODE=-502, SQLCODE=-514, SQLCODE=-518) is marked retryable. For plain read queries the driver can reconnect and retry internally; for prepared statements and transactions, recreate the prepared statement or retry the whole transaction body because those resources are bound to one server session.

Active close mode

Set DB2_ZOS_LOB_CLOSE_AFTER_MATERIALIZE=1 when preserving the same DB2 connection is more important than individual large-LOB query latency:

bash
DB2_ZOS_LOB_CLOSE_AFTER_MATERIALIZE=1 node app.js

The driver sends CLSQRY, drains remaining EXTDTA, waits for DB2's close acknowledgement, and only then returns the connection to the pool.

Keep DB2_ZOS_LOB_TRUST_PASSIVE_TAIL_QUIET off in production. It is fail-closed, but it is not a useful performance path for large z/OS CLOB workloads.

Production soak coverage for the current 1.0.x release line:

ModeCyclesResult
Default disconnect + warm replacement100/100Passed
Active close50/50Passed

Both soaks completed with no wrong row counts, zero-row corruption, stale EXTDTA, or unhandled driver errors.

Development Setup

To run a local DB2 instance for development and testing:

bash
# Clone the repository
git clone https://github.com/gurungabit/db2-node.git
cd db2-node

# Start DB2 in Docker (takes 2-5 min on first run)
./tools/db2.sh start

# DB2 is now running at localhost:50000
# Database: testdb
# User: db2inst1
# Password: db2wire_test_pw

See the Contributing guide for full development instructions.

Released under the MIT License.