Skip to content

Repository files navigation

GraphVault TS

CI npm Node TypeScript License

GraphVault logo

The embedded database for TypeScript object graphs.

GraphVault persists the TypeScript domain model you already use: a root object with nested objects, arrays, maps, sets, shared references, cycles, and classes. It is designed for NestJS services, local-first tools, CLIs, desktop apps, simulations, and other applications that own a rich, connected model.

It is not a SQL server and it is not an ORM. Keep normal objects in memory, change them in ordinary TypeScript, then explicitly commit a verifiable graph store with WAL recovery, locking, indexes, GVQL, and an admin UI.

Current release: 0.2.9, with annotation-driven field constraints, stronger public TSDoc, production write defaults, explicit Node.js LTS support, field annotations for save/load filtering, professional persistent indexes, and NestJS smoke tests.

Why GraphVault?

When a TypeScript model is truly a graph, persisting it through records or JSON often means building an extra mapping layer and reassembling relationships after every read. GraphVault keeps the model as the source of truth.

If you need to... GraphVault gives you...
preserve object identity, cycles, Map, Set, and classes native object-graph persistence instead of a hand-built mapper
decide precisely when data becomes durable explicit commits, transactions, WAL recovery, and locking
query a committed graph without shipping it elsewhere GVQL, persistent indexes, execution plans, aggregates, previews, and batch updates
run an application-owned store safely verification, backups, health reports, schema migrations, and GraphVault Studio
use an embedded store from NestJS a NestJS module plus transactional service decorators

GraphVault is deliberately focused: it is an embedded, application-owned store, not a replacement for Postgres, SQLite, or a distributed database server.

30-Second Quickstart

npm install @sprengmeister/graphvault
import { EmbeddedStorage } from "@sprengmeister/graphvault";

const document = { id: "doc-1", title: "Hello object graph" };

const storage = await EmbeddedStorage.start({
  storageDirectory: "./data",
  root: { documents: [], pinned: new Set() },
});

storage.root.documents.push(document);
storage.root.pinned.add(document); // the same object can be referenced in more than one place
await storage.storeRoot();
await storage.shutdown();

When GraphVault Is A Strong Fit

Use GraphVault when:

  • your app owns a rich object model and you do not want to flatten it into tables
  • object identity, shared references, cycles, classes, Map, Set, and rich JS values matter
  • you want embedded persistence for a NestJS service, CLI, desktop app, simulation, rules engine, local-first tool, test harness, or admin-heavy internal tool
  • writes should be explicit and auditable instead of hidden behind ORM change tracking
  • a bounded graph slice should be easy to expose through an API with loadSubtree({ depth })

When To Choose Something Else

Reach for Postgres, SQLite, MongoDB, or Redis when:

  • many unrelated systems need to write independently into the same database
  • SQL compatibility, mature DBA tooling, replication, external roles, and ad-hoc reporting are central
  • your data model is mostly records and indexes rather than a connected object graph
  • you need a replicated consensus database rather than an embedded application-owned store

Core Capabilities

  • Persist rich TypeScript object graphs with identity, shared references, cycles, classes, Map, Set, Date, Buffer, bigint, typed arrays, and other JS values.
  • Exclude sensitive or runtime-only class fields with field decorators such as @GraphVaultIgnore(), @GraphVaultIgnoreSave(), and @GraphVaultIgnoreLoad().
  • Enforce simple DB-style field constraints with annotations such as @GraphVaultRequired(), @GraphVaultUnique(), @GraphVaultEnum(...), @GraphVaultMin(...), @GraphVaultMax(...), and @GraphVaultReferenceExists().
  • Query and batch-update committed graphs with GVQL, persistent indexes, execution plans, aggregates, previews, and GraphVault Studio.
  • Run explicit transactions with rollback, optimistic or pessimistic locking, WAL recovery, fencing tokens, transaction metadata, and a tamper-evident hash chain.
  • Operate stores with health/safety reports, verification, consistent backup, schema migrations, bounded subtree exports, and pluggable local, memory, HTTP, S3-compatible, SQLite-tested, and PostgreSQL-tested SQL storage targets.

NestJS In A Minute

GraphVault ships a NestJS module and a transaction decorator. The package smoke test installs a fresh NestJS 11 project, compiles this style of setup, writes data, verifies rollback, runs GVQL, closes the app, and reloads persisted data.

import { Injectable, Module } from "@nestjs/common";
import { GraphVaultModule, GraphVaultTransactional, StorageManager } from "@sprengmeister/graphvault";

class AppRoot {
  notes: Array<{ id: string; title: string; status: "draft" | "approved" }> = [];
}

@Injectable()
class NotesService {
  constructor(readonly storage: StorageManager<AppRoot>) {}

  @GraphVaultTransactional({ mode: "pessimistic", managerProperty: "storage" })
  async approve(id: string): Promise<void> {
    const note = this.storage.root.notes.find((item) => item.id === id);
    if (!note) throw new Error(`Unknown note ${id}`);
    note.status = "approved";
  }
}

@Module({
  imports: [
    GraphVaultModule.forRoot<AppRoot>({
      global: true,
      storageDirectory: "./data/graphvault",
      rootFactory: () => new AppRoot(),
      lockStrategy: "pessimistic",
      transactionLog: "full",
      recoverCommittedWal: true,
      readCommittedWal: true,
      staleLockTimeoutMs: 60_000,
    }),
  ],
  providers: [NotesService],
})
export class AppModule {}

See NestJS integration.

Admin UI

GraphVault Studio is the separate graphical admin client for browsing, searching, verifying, backing up, and editing stores.

npm install graphvault-studio
npx graphvault-studio --dir ./data/graphvault --port 4177

Then open http://127.0.0.1:4177.

Performance Snapshot

The benchmark is reproducible with npm run benchmark; a comparative JSON/SQLite/GraphVault benchmark is available with npm run benchmark:compare. The full tables live in docs/BENCHMARKS.md. Latest local run on macOS/Apple Silicon:

target documents storeRoot indexed GVQL aggregate reload storage size
memory 100 21.8 ms 2.5 ms 5.0 ms -
filesystem/production 100 60.1 ms 2.2 ms 31.9 ms 0.44 MiB
filesystem/inspect 100 2856.9 ms 1.7 ms 40.7 ms 1.02 MiB
memory 750 76.5 ms 8.5 ms 20.8 ms -
filesystem/production 750 323.1 ms 8.9 ms 197.0 ms 2.88 MiB
filesystem/inspect 750 19891.3 ms 8.7 ms 244.6 ms 6.62 MiB

The default filesystem profile is writeProfile: "production": binary object records, compact metadata, no debug-oriented duplicate object writes, and higher local write concurrency. Use writeProfile: "inspect" when human-readable JSON sidecars and conservative local flush behavior matter more than write throughput.

Important Workflows

  • Query and manipulate graphs with GVQL: graph patterns, joins, aggregates, execution plans, previews, and batch updates.
  • Keep sensitive or runtime-only model fields out of persistence with field annotations.
  • Keep invalid data out of committed stores with constraint annotations: required fields, type checks, enums, min/max, unique keys, and reference existence checks before WAL publish.
  • Keep large stores fast with persistent indexes: property, composite, range, text/substring, full-text token, unique, partial/sparse, and expression indexes with verify/repair operations.
  • Protect concurrent writers with transactions: rollback, optimistic and pessimistic locking, fencing tokens, stale-lock recovery, and NestJS decorators.
  • Run production checks with operations guidance and ACID configuration: WAL recovery, strict durability, verification, backups, health reports, and safety profiles.
  • Expose bounded graph slices with subtree loading and NestJS REST examples.
  • Evolve persisted roots with schema migrations: storage-wide up and down steps committed through the same transaction path as application writes.

Current Boundaries

GraphVault is intentionally application-owned embedded storage, not a drop-in replacement for a server database. It does not provide SQL wire-protocol compatibility, external user/role management, built-in replication, or distributed consensus. Multi-pod writers can share a store through the configured storage target and GraphVault's lock/transaction path, but high-availability replication and quorum semantics remain an infrastructure concern.

For critical production workloads, read Guarantees and boundaries, ACID configuration, and Production operations, run the storage-target conformance tests for any custom target, and use application-specific commitValidators for domain invariants.

Example Project

npm run build
node examples/basic.mjs

Open the generated store with GraphVault Studio:

npm install graphvault-studio
npx graphvault-studio --dir ./graphvault-example-store --port 4177

Then open http://127.0.0.1:4177.

For a fuller graph-shaped product demo, see the CaseGraph demo concept: an investigation/case-management app where people, companies, accounts, payments, documents, notes, hypotheses, and timeline events form one navigable object graph.

Documentation

  • Usage guide - modeling roots, registering classes, writing data, lazy data, cycles, verification, and lifecycle.
  • Guarantees and boundaries - the precise contract for ACID-oriented behavior, storage-target requirements, tested paths, and when not to use GraphVault.
  • ACID configuration - WAL, recovery, fencing tokens, validators, and durability tradeoffs.
  • Production operations - production profiles, backup/restore, verification, monitoring, and known boundaries.
  • GVQL guide - graph queries, indexed filtering, aggregates, execution plans, and mutation previews.
  • Persistent indexes - storage-wide index configuration, consistency modes, and rebuild operations.
  • Transactions and concurrency - optimistic and pessimistic locking for multi-pod writers.
  • Storage configuration - local filesystem, memory, HTTP, S3-compatible, SQL, and operational options.
  • NestJS integration - module setup, async config, multiple stores, and shutdown hooks.
  • CaseGraph demo concept - the reference use case for graph-shaped, audit-heavy application data.
  • API reference - public entry points and important options.
  • Benchmarks - reproducible performance numbers and write profiles.
  • 0.2.9 release notes - annotation-driven storage constraints for required, type, enum, min/max, unique, and reference checks.
  • 0.2.8 release notes - public API TSDoc hardening and source-quality enforcement.
  • 0.2.7 release notes - production write defaults and renamed write profiles.
  • 0.2.6 release notes - explicit Node.js 22+ LTS support and CI validation.
  • 0.2.5 release notes - field annotations for save/load filtering and current package baseline.
  • 0.2.4 release notes - professional persistent indexes, index verification/repair, and current package baseline.
  • 0.2.3 release notes - NestJS smoke tests and TypeScript developer polish.
  • 0.2.0 release notes - production hardening, ACID-oriented recovery, subtree exports, and encrypted storage.
  • 0.1.0 release notes - package overview for the first public release.
  • Publishing checklist - local release checks, tagging, npm provenance, and GitHub topics.

Help Others Find GraphVault

If GraphVault has removed persistence glue from a TypeScript project, please star the repository. It is a small signal that helps developers with graph-shaped models discover the project.

Developer Experience

npm ci
npm test
npm run benchmark:check
npm run pack:dry-run
npm run package:smoke

The smoke test stores and reloads a real object graph with class instances, shared references, maps, sets, and cycles. The package smoke test installs the generated tarball into a clean temporary project, verifies public and Studio-facing subpath imports, and compiles/runs a minimal NestJS app with injection, rollback, GVQL, health checks, backup, and restart persistence. CI runs on Node.js 22 LTS, 24 LTS, and 26, and includes a source-size quality gate.

Status And Scope

This is an early TypeScript implementation. The storage format is GraphVault-native, not a database-server protocol and not a JVM binary format. The project is designed for production discipline: explicit commits, verification, recovery paths, locking, and readable storage artifacts.

About

GraphVault TypeScript object graph persistence library.

Resources

Contributing

Stars

4 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages