{"id":16702,"library":"xitdb","title":"xitdb Immutable Database","description":"xitdb (current version 0.13.0) is an embedded, immutable database library for TypeScript and JavaScript, designed for storing and managing structured data in a versioned manner. It excels by efficiently creating a new \"copy\" of the database with each transaction, allowing past states to be read from or reverted to. Unlike traditional databases, xitdb operates without a query engine, instead providing direct APIs to manipulate core data structures like ArrayList and HashMap, which can be nested arbitrarily. It supports both single-file and in-memory storage, incrementally reading and writing to handle datasets larger than available memory. A key differentiator is its entirely synchronous API, eliminating the need for `async/await`, and its pure TypeScript implementation with no external dependencies beyond the JavaScript standard library. Reads never block writes, and multiple threads/processes can access the database concurrently without locks. This makes it a powerful alternative to SQL databases like SQLite for applications requiring simplicity, immutability, and tight integration with native TypeScript data structures, especially in scenarios akin to version control systems. The project is under active development, with an irregular, feature-driven release cadence, reflecting its 0.x version status.","status":"active","version":"0.13.0","language":"javascript","source_language":"en","source_url":"https://github.com/xit-vcs/xitdb-ts","tags":["javascript","typescript"],"install":[{"cmd":"npm install xitdb","lang":"bash","label":"npm"},{"cmd":"yarn add xitdb","lang":"bash","label":"yarn"},{"cmd":"pnpm add xitdb","lang":"bash","label":"pnpm"}],"dependencies":[],"imports":[{"note":"xitdb is primarily designed for ESM; CJS usage might require careful transpilation or specific build configurations.","wrong":"const Database = require('xitdb').Database","symbol":"Database","correct":"import { Database } from 'xitdb'"},{"note":"CoreBufferedFile is a named export for file-based database persistence.","wrong":"import CoreBufferedFile from 'xitdb'","symbol":"CoreBufferedFile","correct":"import { CoreBufferedFile } from 'xitdb'"},{"note":"Use WriteArrayList for mutable operations within a transaction; ReadArrayList is for immutable reads. Be precise with the 'Write' prefix.","wrong":"import { ArrayList } from 'xitdb'","symbol":"WriteArrayList","correct":"import { WriteArrayList } from 'xitdb'"},{"note":"The Hasher class is used to specify the hashing algorithm for the database, typically SHA-1 as shown in examples.","wrong":"const Hasher = require('xitdb')","symbol":"Hasher","correct":"import { Hasher } from 'xitdb'"}],"quickstart":{"code":"import { CoreBufferedFile, Database, Hasher, WriteArrayList, WriteHashMap, Bytes, Uint } from 'xitdb';\nimport * as path from 'path';\nimport * as fs from 'fs';\n\nconst dbFilePath = path.join(process.cwd(), 'main.db');\n\n// Ensure the database file doesn't exist from a previous run\nif (fs.existsSync(dbFilePath)) {\n  fs.unlinkSync(dbFilePath);\n}\n\n// init the db\nusing core = new CoreBufferedFile(dbFilePath);\nconst hasher = new Hasher('SHA-1');\nconst db = new Database(core, hasher);\n\n// to get the benefits of immutability, the top-level data structure\n// must be an ArrayList, so each transaction is stored as an item in it\nconst history = new WriteArrayList(db.rootCursor());\n\n// Execute a transaction to add data\nhistory.appendContext(history.getSlot(-1), (cursor) => {\n  const moment = new WriteHashMap(cursor);\n\n  moment.put('foo', new Bytes('foo'));\n  moment.put('bar', new Bytes('bar'));\n\n  const fruitsCursor = moment.putCursor('fruits');\n  const fruits = new WriteArrayList(fruitsCursor);\n  fruits.append(new Bytes('apple'));\n  fruits.append(new Bytes('pear'));\n  fruits.append(new Bytes('grape'));\n\n  const peopleCursor = moment.putCursor('people');\n  const people = new WriteArrayList(peopleCursor);\n\n  const aliceCursor = people.appendCursor();\n  const alice = new WriteHashMap(aliceCursor);\n  alice.put('name', new Bytes('Alice'));\n  alice.put('age', new Uint(25));\n\n  const bobCursor = people.appendCursor();\n  const bob = new WriteHashMap(bobCursor);\n  bob.put('name', new Bytes('Bob'));\n  bob.put('age', new Uint(42));\n});\n\n// Read the most recent state of the database\nconst latestMomentCursor = history.getSlot(-1);\nif (latestMomentCursor) {\n  const latestMoment = new WriteHashMap(latestMomentCursor);\n  console.log('Database state after transaction:');\n  // You would typically iterate or access specific keys here\n  // For demonstration, let's just confirm an item exists\n  console.log('Has \"foo\" key:', latestMoment.get('foo')?.toString());\n  console.log('Has \"fruits\" key:', latestMoment.get('fruits') !== undefined);\n} else {\n  console.log('No data found in the database history.');\n}\n\n// Clean up the database file (optional, for repeated runs)\n// fs.unlinkSync(dbFilePath);","lang":"typescript","description":"This example initializes a file-backed xitdb, performs a transaction to write structured data, and then reads the latest state."},"warnings":[{"fix":"Always pin to exact versions (e.g., `\"xitdb\": \"0.13.0\"`) or use a version range that accounts for potential breaking changes (e.g., `\"xitdb\": \"^0.13.0\"` with caution).","message":"As xitdb is currently in version 0.x.y, the API is not yet stable, and breaking changes may occur between minor or even patch releases. Review changelogs carefully when upgrading.","severity":"breaking","affected_versions":">=0.1.0"},{"fix":"Embrace direct object manipulation. Design your data schema to align with nested ArrayLists and HashMaps for efficient access within your application logic.","message":"xitdb does not include a query engine. Data access and manipulation are performed directly through JavaScript/TypeScript data structures (ArrayList, HashMap). Developers accustomed to SQL or NoSQL query languages will need to adapt.","severity":"gotcha","affected_versions":">=0.1.0"},{"fix":"Ensure all write operations are performed within the context function passed to `history.appendContext()`, using `WriteArrayList` and `WriteHashMap` objects.","message":"The database is immutable; transactions always create new versions. Attempting to modify data in-place on a read cursor will not work. Always operate on `WriteArrayList` or `WriteHashMap` instances obtained within a transaction's context.","severity":"gotcha","affected_versions":">=0.1.0"},{"fix":"For client-side applications or Node.js servers, consider offloading intensive xitdb operations to Web Workers or child processes to prevent blocking the main thread. In embedded or CLI tools, this is less of a concern.","message":"The API is entirely synchronous, which can be unexpected for I/O-heavy operations in modern JavaScript/TypeScript development. This design decision simplifies usage but requires careful consideration in environments where blocking the event loop is problematic.","severity":"gotcha","affected_versions":">=0.1.0"},{"fix":"For security-sensitive use cases outside of xitdb's internal data integrity, use modern cryptographic hash functions like SHA-256 or SHA-3, or libraries designed for password hashing (e.g., bcrypt).","message":"The quickstart example uses 'SHA-1' for hashing. While suitable for internal database integrity, SHA-1 is cryptographically broken and should not be used for security-sensitive applications like password hashing or digital signatures.","severity":"gotcha","affected_versions":">=0.1.0"}],"env_vars":null,"last_verified":"2026-04-22T00:00:00.000Z","next_check":"2026-07-21T00:00:00.000Z","problems":[{"fix":"Ensure you are within a `history.appendContext` callback and are using `WriteHashMap` or `WriteArrayList` instances created from the provided `cursor`.","cause":"Attempting to call a write method (like `put` or `append`) on a `ReadHashMap` or `ReadArrayList` instance, or on a cursor obtained outside of a transaction context.","error":"TypeError: Cannot read properties of undefined (reading 'put')"},{"fix":"Ensure `CoreBufferedFile` instances are properly closed or disposed of when no longer needed. If using `using` declarations, ensure they are within the correct scope to manage resources. Avoid opening the same file multiple times in parallel within a single process unless explicitly designed for it.","cause":"Trying to instantiate `CoreBufferedFile` with the same file path multiple times concurrently or without properly disposing of previous instances.","error":"Error: File already open"},{"fix":"Verify that `history` is indeed an instance of `WriteArrayList` initialized from the database's root cursor, as this is the standard entry point for transactions.","cause":"Trying to call `appendContext` on an object that is not a `WriteArrayList` (or `WriteHashMap` in its capacity to append to a list within).","error":"TypeError: history.appendContext is not a function"},{"fix":"Add `import { Hasher } from 'xitdb';` to the top of your TypeScript/JavaScript file.","cause":"The `Hasher` class was used without being imported.","error":"ReferenceError: Hasher is not defined"}],"ecosystem":"npm"}