Node.js Embedded
Run Traverse as an in-process graph database in Node.js applications.
Install
npm install @truespar/traverse-node
Note: The package includes prebuilt native bindings via napi-rs. Supported on Windows, Linux, and macOS.
Open a Database
const traverse = require('@truespar/traverse-node');
// Open or create a database (file is created on first flush)
const db = traverse.open('mydb.tvdb');
Run Queries
const tx = db.begin();
const result = tx.execute('MATCH (n:Person) RETURN n.name, n.age');
for (const row of result.rows) {
console.log(row['n.name'], row['n.age']);
}
tx.abort(); // read-only, no changes to commit
Query Parameters
const tx = db.begin();
const result = tx.execute(
'MATCH (n:Person) WHERE n.age > $minAge RETURN n.name',
{ minAge: 25 }
);
for (const row of result.rows) {
console.log(row['n.name']);
}
tx.abort();
Write Data
const tx = db.begin();
tx.execute("CREATE (p:Person {name: 'Alice', age: 30})");
tx.execute("CREATE (p:Person {name: 'Bob', age: 25})");
tx.commit();
Note: You must call commit() to persist changes. If neither commit() nor abort() is called, changes are discarded when the transaction is garbage collected.
Transactions
let tx = db.begin();
tx.execute("CREATE (p:Person {name: 'Carol'})");
tx.execute(
"MATCH (a:Person {name: 'Alice'}), (b:Person {name: 'Carol'}) " +
"CREATE (a)-[:KNOWS]->(b)"
);
tx.commit();
// Verify
tx = db.begin();
const result = tx.execute('MATCH (a)-[:KNOWS]->(b) RETURN a.name, b.name');
console.log(result.rows[0]['a.name'], result.rows[0]['b.name']);
tx.abort();
QueryResult
const tx = db.begin();
const result = tx.execute('MATCH (n:Person) RETURN n.name, n.age');
console.log(result.columns); // ['n.name', 'n.age']
console.log(result.rowCount); // number of rows
// Rows are an array of objects
for (const row of result.rows) {
console.log(row['n.name']);
}
// Mutation statistics
const writeResult = tx.execute('CREATE (n:Test)');
console.log(writeResult.stats.nodesCreated); // 1
tx.abort();
Bulk Writer
The BulkWriter bypasses MVCC for high-throughput imports (2–5M rows/s).
const writer = db.bulkWriter();
const nid1 = writer.createNode(['Person'], { name: 'Alice', age: 30 });
const nid2 = writer.createNode(['Person'], { name: 'Bob', age: 25 });
writer.createEdge(nid1, nid2, 'KNOWS', { since: 2024 });
writer.commit();
Nodes can be created with labels only:
const nid = writer.createNode(['Company', 'Active']);
Edges can be created without properties:
writer.createEdge(sourceId, targetId, 'WORKS_AT');
Indexes
Create indexes via the bulk writer or Cypher:
// Via BulkWriter
const writer = db.bulkWriter();
writer.createIndex('idx_person_name', 'Person', 'name');
writer.createEdgeIndex('idx_knows_since', 'KNOWS', 'since');
writer.createEdgeIndex('idx_knows', 'KNOWS'); // type-only index
writer.commit();
// Via Cypher
const tx = db.begin();
tx.execute('CREATE INDEX idx_person_age FOR (n:Person) ON (n.age)');
tx.commit();
Drop an edge index:
const writer = db.bulkWriter();
writer.dropEdgeIndex('idx_knows_since');
writer.commit();
Flush and Close
// Flush dirty pages to disk
db.flush();
// Close the database
db.close();
Note: Traverse is an in-memory database. Call flush() to persist data to the .tvdb file. Data written since the last flush is lost if the process crashes.