Skip to content

API reference

Low-level API

Direct database primitives

The low-level API uses the Database class for direct graph operations, transaction control, and batched writes.

Open and write

TypeScript
import { Database, PropValueType } from '@kitedb/core';const db = Database.open('./data.kitedb', { createIfMissing: true });db.begin();try {  const nodeId = db.createNode('user:alice');  db.setNodePropByName(nodeId, 'name', {    propType: PropValueType.String,    stringValue: 'Alice',  });  db.commit();} catch (err) {  db.rollback();  throw err;}

Database.open() takes the MVCC options; MVCC is on by default and mvcc: false is deprecated. A commit that conflicts with a write committed since its transaction began throws an Error whose message reads Failed to commit: Transaction <id> conflict on keys: [...]. The transaction has then ended and nothing was applied; run it again.

Batch operations

beginBulk() starts a bulk-load transaction, the fastest way to load data, with MVCC on or off. It runs alone among writers: it waits for open write transactions to finish, and write transactions that begin while it is open wait for it. Readers never wait for it, and a read transaction that began before its commit does not see it.

TypeScript
// High-throughput bulk ingestdb.beginBulk();const nodeIds = db.createNodesBatch(keys); // Array<string | null>db.addEdgesBatch(edges);                   // Array<{ src, etype, dst }>db.addEdgesWithPropsBatch(edgesWithProps);db.commit();// Optional maintenance checkpoint after ingestdb.checkpoint();

bulkWrite() runs a list of synchronous operations in bulk-load transactions of chunkSize operations each (default 1000), committing after each chunk.

TypeScript
import { bulkWrite } from '@kitedb/core';const nodeIds = bulkWrite(  db,  keys.map((key) => (d) => d.createNode(key)),  { chunkSize: 5000 },);

Checkpoints

A checkpoint folds the log (the WAL, and the WAL segments a full WAL spills into) into a new snapshot. Automatic checkpoints run on a thread of the database's own; see When checkpoints happen. Database.open() takes these options. kite() takes the same ones except autoCheckpoint and backgroundCheckpoint, with walSizeMb in place of walSize.

OptionDefaultDescription
walSize4 MBBytes of the WAL area, fixed when the file is created. A full WAL spills into a WAL segment. Besides how often it spills, it sets the floors of the checkpoint trigger (3/8 of the WAL), the segment limit (16 WALs) and the segment extent (2 WALs)
autoCheckpointtrueCheckpoint automatically. Without it, the WAL spills into segments up to walSegmentLimit, then writes fail until a checkpoint
backgroundCheckpointtrueAutomatic checkpoints run while writes continue; false makes them blocking (they run after a commit, and a writer at walSegmentLimit fails instead of waiting; one runs once its transaction ends)
checkpointThreadtrueRun automatic background checkpoints on the database's checkpoint thread, so the commit that crosses the trigger returns at once; false runs them on the committing thread
checkpointLogRatio0.5Checkpoint once the log the snapshot does not cover reaches this fraction of the snapshot's size (at least 3/8 of the WAL, where earlier releases checkpointed; at most checkpointLogBudget)
checkpointLogBudget128 MiBThe most log, in bytes, an automatic checkpoint waits for. The in-memory delta takes about ten times the log's size, so this bounds its memory while checkpoints keep up (writers that outrun them grow the log up to walSegmentLimit)
walSegmentSize1/16 of the segment limit, from 2 WALs to max(32 MiB, 2 WALs)Bytes of a WAL segment extent (never less than 1.5 WALs). An open transaction keeps the extent it began in whole until a checkpoint covers its commit, so extents stay small next to the limit
walSegmentLimitTwice the trigger, at least 16 WALs, at most four times checkpointLogBudgetThe most bytes of WAL segments. At the limit, writers wait for a checkpoint to free some; before it, while a background checkpoint runs past the trigger, each commit waits up to 100 ms so the room left lasts the run (and once per run, a commit may wait for the install, for a time that grows with the delta). The segment table also caps them at 63 extents: with default extents, about four times a limit up to 512 MiB, and 2 GiB beyond; with walSegmentSize set, 63 extents of it
checkpointThresholdnoneDeprecated, no effect. Still accepted (0 to 1); use checkpointLogRatio and checkpointLogBudget
TypeScript
db.checkpoint();           // blocking: waits for open transactions, leaves no WAL segmentsdb.backgroundCheckpoint(); // writes continue; runs on this thread, returns after its installdb.shouldCheckpoint(0.8);  // has the uncovered log reached 0.8 of the trigger? (default 0.8)db.checkpointError();      // the last automatic checkpoint's error, or nulldb.close();                // a clean close checkpoints any WAL segments away

A failed automatic checkpoint, on the checkpoint thread or inline, reports nothing to the commit that started it. Its error is logged and returned by checkpointError() (also on Kite; checkpoint_error() on a Python Database) until a checkpoint succeeds, and the next automatic checkpoint waits out a back-off (1 s, doubling to 60 s while failures go on; any checkpoint that succeeds ends it). While the last one failed, a writer that finds the WAL segments full fails with Checkpoint failed, and the WAL segments are full: ... (CheckpointError in Python) instead of waiting. backgroundCheckpoint() declines (Background checkpoint declined: ...; CheckpointDeclinedError in Python) while a blocking checkpoint or compaction waits for the gate, or when open write transactions hold every WAL segment.

Long-running calls

Calls that can take a long time have *Async variants that run on the libuv thread pool and return a Promise, so the event loop keeps serving other work: checkpointAsync(), optimizeAsync(), vacuumAsync(), exportToJsonAsync(), exportToJsonlAsync(), importFromJsonAsync(), waitForTokenAsync(), and the functions createBackupAsync(), restoreBackupAsync(), createOfflineBackupAsync() and the pushReplicationMetricsOtel*Async() pushes. They reject inside a transaction (commit or roll back first), and close() fails while one is still running.

TypeScript
await db.checkpointAsync();const reached = await db.waitForTokenAsync(token, 5_000);

Streaming and pagination

streamNodes() returns all node IDs split into batches. get_nodes_page() returns one page of node IDs and a cursor for the next page. It is snake_case in the TypeScript bindings.

TypeScript
// Node IDs in fixed-size batchesfor (const batch of db.streamNodes({ batchSize: 1000 })) {  for (const nodeId of batch) {    // process nodeId  }}// Cursor paginationlet cursor: string | undefined = undefined;do {  const page = db.get_nodes_page({ limit: 100, cursor });  for (const nodeId of page.items) {    // process nodeId  }  cursor = page.nextCursor;} while (cursor);