Skip to content

Getting started ​

Prerequisites ​

  • Bun v1.4.0+ (required for bun:ffi; tested on 1.4.0 — Bun 1.3.x is not supported because of FFI cleanup crashes).
  • Linux x86_64 only — the FFI layer loads a native shared library and refuses to import anywhere else (process.platform === "linux" and process.arch === "x64", enforced at load time).
  • glibc 2.38+ — the native binaries are dynamically linked against glibc. Older distros (Debian 11 "bullseye", Ubuntu 20.04 "focal", RHEL 8, and older) fail at dlopen() time with libnostrdb.so: cannot open shared object file: GLIBC_2.38 not found (__isoc23_strtol is the highest required symbol).
  • The native library, built from the pinned nostrdb submodule:

Compatibility matrix ​

ComponentMinimumTestedNotes
OSLinux x86_64Linux x86_64Enforced at load time. macOS/Windows are out of scope.
glibc2.382.43libnostrdb.so requires GLIBC_2.38. Older distros fail at dlopen() time.
Bun1.4.01.4.0Required for bun:ffi. Bun 1.3.x is not supported because of FFI cleanup crashes.

Source builds additionally need a C toolchain (build-essential or equivalent), GNU Make (not BSD Make), and GNU coreutils (file, grep, find). npm consumers skip this — bun add bunostrdb ships prebuilt Linux x86_64 shared objects.

bash
bun run build:native

This produces packages/bunostrdb/native/libnostrdb.so (+ the struct-by-value shim). The loader verifies the submodule commit at import time and throws if the .so was built from anything else.

Install ​

bash
bun add bunostrdb

Your first database ​

ts
// @ts-nocheck
import { buildDraftNote, BunNdb, FilterBuilder } from "bunostrdb";

// A missing directory is created for you — first run just works.
{
	using ndb = new BunNdb("./data");
	// Signed sample event — drafts are real events, so they ingest cleanly.
	const { event } = buildDraftNote("hello local world");

	// Ingest: queue one event (JSON string) for the background parser,
	// then wait until it is committed before reading it back.
	ndb.processEvent(JSON.stringify(["EVENT", "sub1", event]));
	await ndb.waitForNoteById(event.id);

	// Query: build a filter, read matches — `using` destroys the filter.
	using filter = new FilterBuilder().kinds([1]).limit(10).build();
	for (const note of ndb.query([filter], 10)) {
		console.log(note.id, note.content);
	}

	// Search: ranked full-text over everything ingested so far.
	console.log(ndb.textSearch("hello", { limit: 10 }).length);
} // ndb destroyed here, even on throw

Ownership rules ​

The FFI layer has no garbage-collector backstop for native memory. Three rules keep you sound:

  1. ndb.destroy() is mandatory — or use using. Nothing frees the database handle for you. using ndb = new BunNdb(...) destroys it at scope exit; otherwise wrap destroy() in try/finally. With a subscription callback, prefer await using (drains posted callbacks via destroyAsync()). See Resource management.
  2. Built filters must be destroyed. builder.build() transfers ownership to the Filter; subscribe() builds and destroys builders internally, but a Filter you hold needs filter.destroy().
  3. Ingestion is asynchronous. processEvent() queues work for the background parser — it does not mean "stored". To observe Committed data, subscribe() + await waitForNotes(subId), or poll with pollForNotes(). The CLI's ingest path waits via waitForNoteById() (default 10s, --timeout <ms>) for the same reason.

Violating lifecycle rules throws NdbError with a Lifecycle code instead of corrupting memory — but the throw is the backstop, not the plan.

Troubleshooting ​

  • mdb_env_open failed — ancient history for missing directories (now auto-created). If you still see it, the path exists as a file or permissions deny creation.
  • NdbError: init at import — the .so doesn't match the pinned nostrdb commit. Rebuild with bun run build:native.
  • GLIBC_2.38 not found at dlopen() — glibc too old (Debian 11, Ubuntu 20.04, RHEL 8). Upgrade the host; there is no static-glibc build.
  • Import errors on other platforms/architectures — expected: Linux x86_64
    • Bun only, enforced at import time. macOS/Windows are out of scope.
  • FFI crashes on Bun 1.3.x — upgrade to Bun 1.4.0+.

Next steps ​

Released under the BSD-3.0 License.