Skip to content

Data types ​

Every Firebird scalar type is supported in both directions — including the Firebird 4 additions that trip up older drivers.

Firebird typeJS read valueJS parameter values
SMALLINT, INTEGERnumbernumber, bigint, string
BIGINTnumber when within ±2^53, else bigint (int64As: 'auto', configurable)number, bigint, string
INT128bigintbigint, number, string
NUMERIC/DECIMAL(p,s)number (lossy beyond 2^53 — see note)string (exact), number, bigint
FLOAT, DOUBLE PRECISIONnumbernumber
DECFLOAT(16/34)string (exact, incl. 'Infinity'/'NaN')string, number
CHAR, VARCHARstringstring
DATE, TIME, TIMESTAMPDateDate
TIME/TIMESTAMP WITH TIME ZONEDate (or ZonedDate, see below)Date, ZonedDate
BOOLEANbooleanboolean
BLOBBuffer/string (eager) or Blob handleBuffer, string, Readable/AsyncIterable

int64As (connection option) controls scale-0 BIGINT decoding: 'auto' (default — number when the value fits safely, bigint otherwise), 'bigint', or 'number'.

Naive TIMESTAMP ⇄ Date uses local wall-clock

A JS Date binds to a timezone-naive TIMESTAMP/DATE/TIME by its local wall-clock components (getFullYear(), getHours(), …) — the right semantics for a column that has no zone, but not the UTC instant that date.toISOString() prints. If your process runs at UTC+2, binding new Date('2026-08-19T10:00:00Z') stores 12:00, and printing the parameter with toISOString() will look two hours off from what lands in the column. Decoding is symmetric (naive values come back as local-wall-clock Dates), so round-trips are lossless. For instant semantics use TIMESTAMP WITH TIME ZONE (bind a ZonedDate or a Date).

Zone-preserving time zone types (FB4+) ​

By default, TIMESTAMP/TIME WITH TIME ZONE columns decode to JS Date — the exact UTC instant, zone dropped. Opt in to keep the zone:

ts
const db = await connect({ …, timeZones: 'zoned' });

const [row] = await db.query("select ts from events");
const z = row.TS;            // ZonedDate { date: Date(UTC instant), zone: 'Europe/Lisbon' | '+02:30' }
z.toString();                // 2026-07-13T14:30:00.000Z[Europe/Lisbon]
z.date.toLocaleString('pt-PT', { timeZone: z.zone });  // wall-clock rendering via Intl

await db.execute('insert into events (ts) values (?)',
  [new ZonedDate(new Date('2026-07-13T14:30:00Z'), 'Europe/Lisbon')]);  // round-trips zone + instant

Named zones come from a table generated from the Firebird source (637 zones, tzdata 2026b); offsets decode as ±HH:MM. Connection-level option (column readers are cached per statement).

DECFLOAT and INT128 ​

DECFLOAT and INT128 are fully supported in both directions (strings/bigints bind losslessly), including the DECFLOAT specials — 'Infinity', '-Infinity' and 'NaN' decode as those strings and bind back as parameters (JS Infinity/NaN numbers work too).

NUMERIC/DECIMAL: numbers out, exact strings in ​

Scaled NUMERIC/DECIMAL columns decode to JS number — convenient for the common case, and documented as lossy beyond 2^53 total digits of scaled value. When you need exactness, keep the money in DECFLOAT (decodes to exact strings) or select cast(col as varchar(…)).

Binding is exact from strings: '0.1' is scaled by string arithmetic, never via parseFloat. This matters doubly in executeBatch, where out-of-range and precision-overflow values are rejected client-side with the offending row's index.

Character sets ​

The charset layer is resolved at prepare time (zero per-cell branching): UTF8 and latin1 use native Buffer fast paths, everything else goes through iconv-lite. Legacy CHARSET NONE databases get a dedicated transcoding toolkit.

MIT Licensed. Contains data derived from the Firebird project under IDPL/IPL.