{"id":16555,"library":"tuple-database","title":"Tuple Database","description":"Tuple Database is a local-first, embedded database designed for modern JavaScript and TypeScript applications, particularly those embracing the local-first software paradigm. It functions as a reactive, indexable graph database, often described as an 'embedded FoundationDb.' The library, currently at version 2.2.4, provides transactional read/write operations with a schemaless approach, where schemas are enforced by the application's type definitions rather than the database itself. It supports both synchronous and asynchronous storage backends, including SQLite or LevelDb, making it versatile for various environments. Key differentiators include its focus on freeing developers from the complexities of multi-tenant systems by empowering users with local data ownership, offering all reactive queries, and enabling direct manipulation of indexes for graph and relational queries. While the release cadence isn't explicitly stated, active development is indicated by its `2.x.x` versioning and comprehensive feature set, positioning it as a robust solution for frontend state management and embedded data persistence.","status":"active","version":"2.2.4","language":"javascript","source_language":"en","source_url":"https://github.com/ccorcos/tuple-database","tags":["javascript","typescript"],"install":[{"cmd":"npm install tuple-database","lang":"bash","label":"npm"},{"cmd":"yarn add tuple-database","lang":"bash","label":"yarn"},{"cmd":"pnpm add tuple-database","lang":"bash","label":"pnpm"}],"dependencies":[{"reason":"Peer dependency required for using the `useTupleDatabase` React hook for reactive data access within components.","package":"react","optional":true}],"imports":[{"note":"The library primarily uses ESM imports; CommonJS `require` might lead to issues in modern environments or bundling.","wrong":"const TupleDatabaseClient = require('tuple-database').TupleDatabaseClient","symbol":"TupleDatabaseClient","correct":"import { TupleDatabaseClient } from 'tuple-database'"},{"note":"This is a named export, not a default export. Ensure curly braces are used.","wrong":"import transactionalReadWrite from 'tuple-database'","symbol":"transactionalReadWrite","correct":"import { transactionalReadWrite } from 'tuple-database'"},{"note":"The React hook `useTupleDatabase` is exported from a specific subpath, not the main package entry point.","wrong":"import { useTupleDatabase } from 'tuple-database'","symbol":"useTupleDatabase","correct":"import { useTupleDatabase } from 'tuple-database/useTupleDatabase'"}],"quickstart":{"code":"import { TupleDatabaseClient, TupleDatabase, InMemoryTupleStorage, transactionalReadWrite } from \"tuple-database\";\n\n// 1. Define your schema using TypeScript types.\ntype User = {\n  id: string;\n  first_name: string;\n  last_name: string;\n  age: number;\n};\n\ntype UserIndex = {\n  key: [\"user\", { id: string }],\n  value: User;\n};\n\ntype AgeIndex = {\n  key: [\"userByAge\", { age: number }, { id: string }],\n  value: null;\n};\n\ntype Schema = UserIndex | AgeIndex;\n\n// 2. Construct your database with an in-memory storage.\nconst db = new TupleDatabaseClient<Schema>(new TupleDatabase(new InMemoryTupleStorage()));\n\n// 3. Define a transactional write query.\nconst insertUser = transactionalReadWrite<Schema>()((tx, user: User) => {\n  const { id, first_name, last_name, age } = user;\n  tx.set([\"user\", { id }], user);\n  tx.set([\"userByAge\", { age }, { id }], null);\n});\n\n// 4. Insert some data.\ninsertUser(db, { id: \"1\", first_name: \"Chet\", last_name: \"Corcos\", age: 31 });\ninsertUser(db, { id: \"2\", first_name: \"Tanishq\", last_name: \"Kancharla\", age: 22 });\nconsole.log(\"Users inserted.\");\n\n// 5. Define a read query to get users by age.\nfunction getUsersByAge(dbClient: TupleDatabaseClient<Schema>, minAge: number) {\n  return dbClient.scan({ prefix: [\"userByAge\", { age: minAge }], gte: [\"userByAge\", { age: minAge }] });\n}\n\n// 6. Execute a read query and log results.\nconst usersOver30 = getUsersByAge(db, 30);\nconsole.log(\"Users with age >= 30:\", usersOver30.map(entry => entry.key[2].id));\n\n// For React integration:\n// import { useTupleDatabase } from 'tuple-database/useTupleDatabase';\n// function App({db}: {db: TupleDatabaseClient<Schema>}) {\n//   const oldestUser = useTupleDatabase(db, () => {\n//     const [oldestEntry] = db.scan({prefix: [\"userByAge\"], reverse: true, limit: 1});\n//     return oldestEntry ? db.get([\"user\", {id: oldestEntry.key[2].id}]) : null;\n//   }, []);\n//   return <div>The oldest user is age: {oldestUser?.age}</div>;\n// }","lang":"typescript","description":"This quickstart demonstrates defining a schema, initializing an in-memory database, performing transactional writes, and executing reactive scans. It also briefly mentions the React hook for state management."},"warnings":[{"fix":"Rigorously define and maintain your `Schema` TypeScript type. Use generic type parameters with `TupleDatabaseClient` and `transactionalReadWrite` to leverage TypeScript's type checking for all database operations.","message":"Tuple Database is schemaless in its storage layer; schemas are enforced solely by application-level TypeScript types. Inconsistencies can easily arise if the TypeScript schema (`Schema` type) does not accurately reflect how tuples are actually written or read, leading to runtime data retrieval issues or type mismatches.","severity":"gotcha","affected_versions":">=1.0.0"},{"fix":"Review the official changelog and migration guides for each major version upgrade. Update your tuple key definitions and API calls according to the new specifications.","message":"Major version updates (e.g., from v1 to v2) may introduce breaking changes in API surface or internal tuple key structures. While not frequent, always consult the release notes for migration guides.","severity":"breaking","affected_versions":">=2.0.0"},{"fix":"Ensure the `TupleDatabaseClient` instance is explicitly passed as a prop to any React component that uses `useTupleDatabase`. For top-level components, this means providing it from your application's root.","message":"The `useTupleDatabase` React hook requires the `TupleDatabaseClient` instance to be passed as a prop, as it does not rely on React Context for database access. This differs from many other state management libraries.","severity":"gotcha","affected_versions":">=1.0.0"}],"env_vars":null,"last_verified":"2026-04-22T00:00:00.000Z","next_check":"2026-07-21T00:00:00.000Z","problems":[{"fix":"Ensure your tuple keys strictly conform to the `Schema` type definitions, using object literals for named parts of the tuple key (e.g., `['user', {id: userId}]`).","cause":"Attempting to use a simple array of strings instead of a properly structured tuple key (e.g., `['type', {id: '...'}]`) in `get`, `set`, `remove`, or `scan` operations.","error":"Argument of type 'string[]' is not assignable to parameter of type 'Tuple'."},{"fix":"Use ES module `import` statements: `import { Symbol } from 'tuple-database';`. Configure your project's build system (Webpack, Rollup, Vite) or Node.js environment to handle ESM correctly.","cause":"Attempting to import `tuple-database` using CommonJS `require()` syntax in a project configured for ESM (e.g., in a modern Node.js environment with `\"type\": \"module\"` in `package.json` or within a browser module).","error":"TypeError: require is not a function"},{"fix":"Always check if the result of a database operation is `null` or `undefined` before accessing its properties. Use optional chaining (`?.`) or type guards to ensure type safety, e.g., `if (result) { console.log(result.key); }`.","cause":"This error typically occurs when trying to access properties of a `scan` or `get` result without proper TypeScript type narrowing, especially when the result could be `undefined` or `null`.","error":"Property 'key' does not exist on type '{ key: any; value: any; }'."}],"ecosystem":"npm"}