Node and TypeScript

Nexyron runs inside your Node process as a native module, with TypeScript types included.

Opening a database

import { open } from '@nexyron/node';

const db = await open('./business.nexyron');

const rows = await db.query('MATCH (c:Customer) RETURN count(c) AS customers');
console.log(rows[0].customers);

await db.close();

Read this before anything else: identifiers

Always return identifiers as strings with element_id().

const rows = await db.query(`
  MATCH (c:Customer)
  RETURN element_id(c) AS id, c.name AS name
`);

JavaScript numbers cannot represent large integers exactly. An identifier that arrives as a number can be silently rounded, after which it matches nothing. The failure is quiet: no error, just a lookup that returns empty, usually noticed long after the code that caused it.

The same applies to any large integer in your own data, such as external system keys. If a value can exceed roughly nine quadrillion, carry it as a string.

Parameters

const rows = await db.query(
  `MATCH (c:Customer)-[:BELONGS_TO]->(s:Site {name: $site})
   WHERE c.joinedAt >= $since
   RETURN element_id(c) AS id, c.name AS name`,
  { site: 'Bergen', since: '2026-01-01' },
);

Writing and transactions

await db.transaction(async (tx) => {
  await tx.query('CREATE (s:Site {name: $name})', { name: 'Trondheim' });
  await tx.query(
    `MATCH (c:Customer {name: $customer}), (s:Site {name: $site})
     CREATE (c)-[:BELONGS_TO]->(s)`,
    { customer: 'Nora Ellingsen', site: 'Trondheim' },
  );
});

Throwing inside the callback rolls the whole transaction back.

Typing results

Queries return plain objects, so a returned shape can be typed directly:

type SiteRow = { site: string; customers: number };

const rows = await db.query<SiteRow>(`
  MATCH (s:Site)<-[:BELONGS_TO]-(c:Customer)
  RETURN s.name AS site, count(c) AS customers
  ORDER BY customers DESC
`);

The type describes what you returned, so keep RETURN explicit rather than returning whole subjects. Your types then stay accurate as the model grows.

In a server

Open the database once at startup and share it. Opening per request is slow and unnecessary.

// db.ts
import { open } from '@nexyron/node';
export const db = await open(process.env.NEXYRON_PATH ?? './business.nexyron');

Close it on shutdown so the last writes are flushed:

process.on('SIGTERM', async () => {
  await db.close();
  process.exit(0);
});