{"id":14155171,"url":"https://github.com/cross-org/kv","last_synced_at":"2026-02-01T13:16:15.317Z","repository":{"id":238209943,"uuid":"796102148","full_name":"cross-org/kv","owner":"cross-org","description":"A fast, lightweight, powerful and cross-platform key-value database for Node.js, Deno, and Bun.","archived":false,"fork":false,"pushed_at":"2025-11-29T00:22:50.000Z","size":436,"stargazers_count":42,"open_issues_count":1,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-12-01T02:08:24.843Z","etag":null,"topics":["bun","database","deno","javascript","kv","node","nosql","typescript"],"latest_commit_sha":null,"homepage":"https://kv.56k.guru/","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/cross-org.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2024-05-04T23:55:27.000Z","updated_at":"2025-11-29T00:20:41.000Z","dependencies_parsed_at":"2024-08-17T08:04:55.322Z","dependency_job_id":"c6670995-ea02-41a9-8284-f85eb97ec86d","html_url":"https://github.com/cross-org/kv","commit_stats":{"total_commits":76,"total_committers":1,"mean_commits":76.0,"dds":0.0,"last_synced_commit":"ae8d42fb183fa2a6542da32224cc71921a714d3c"},"previous_names":["cross-org/kv"],"tags_count":46,"template":false,"template_full_name":null,"purl":"pkg:github/cross-org/kv","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cross-org%2Fkv","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cross-org%2Fkv/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cross-org%2Fkv/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cross-org%2Fkv/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/cross-org","download_url":"https://codeload.github.com/cross-org/kv/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cross-org%2Fkv/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28978967,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-01T12:13:08.691Z","status":"ssl_error","status_checked_at":"2026-02-01T12:13:08.356Z","response_time":56,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["bun","database","deno","javascript","kv","node","nosql","typescript"],"created_at":"2024-08-17T08:02:20.197Z","updated_at":"2026-02-01T13:16:15.312Z","avatar_url":"https://github.com/cross-org.png","language":"TypeScript","funding_links":[],"categories":["typescript"],"sub_categories":[],"readme":"# @cross/kv\n\nA fast, lightweight, powerful and cross-platform key-value database for Node.js,\nDeno, and Bun.\n\n[![JSR](https://jsr.io/badges/@cross/kv)](https://jsr.io/@cross/kv)\n[![JSR Score](https://jsr.io/badges/@cross/kv/score)](https://jsr.io/@cross/kv)\n\nLibrary usage:\n\n```typescript\nimport { KV } from \"@cross/kv\";\n\n// Create an instance\nconst db = new KV();\nawait db.open(\"data/mydatabase.db\");\n\n// Listen for new interests of any user\ndb.watch([\"users\", {}, \"interests\"], (data) =\u003e {\n  console.log(data);\n});\n\n// Store some values/documents indexed by users.\u003cid\u003e.\u003ccategory\u003e\nawait db.set([\"users\", 1, \"contact\"], {\n  name: \"Bob\",\n});\nawait db.set([\"users\", 1, \"interests\"], {\n  description: \"Fishing\",\n});\n\n// Display all contact information connected to users with id \u003c= 10\nconsole.log(await db.listAll([\"users\", { to: 10 }, \"contact\"]));\n\ndb.close();\n```\n\nCommand line client `ckv`:\n\n```bash\n# Install\n# deno install -frgA --name ckv jsr:@cross/kv/cli\n\n# Run without installing\ndeno run -A jsr:@cross/kv/cli\n\n\u003e open my.db\nSuccess [10.30 ms]\n\n\u003e set:json my.key {\"hello\":\"kv\"}\nSuccess [31.70 ms]\n\n\u003e get my.key\n\nKey:             [\"my\",\"key\"]\nOperation:       SET (1)\nTimestamp:       2024-05-26T19:49:49.471Z\nHash:            abdf6eb7a3fe04af920f31a599ce0cc069d29041\n\n{ hello: \"kv\" }\n\nSuccess [7.74 ms]\n```\n\n## Features\n\n- **Cross-Platform \u0026 Multi-Process:** Built with pure TypeScript for seamless\n  compatibility across Node.js, Deno, and Bun, with built-in support for\n  concurrent access by multiple processes.\n- **Powerful:** Supports hierarchical keys, flexible mid-key range queries, and\n  real-time data change notifications through `.watch()`.\n- **Simple and Fast:** Lightweight and performant storage with an in-memory\n  index for efficient data retrieval.\n- **Durable:** Ensures data integrity and reliability by storing each database\n  as a single, append-only transaction ledger.\n- **Type-Safe:** Leverages TypeScript generics for enhanced type safety when\n  setting and retrieving values.\n- **Atomic Transactions:** Guarantees data consistency by grouping multiple\n  operations into indivisible units, which also improves performance.\n- **Flexible:** Store any serializable JavaScript object (except functions and\n  WeakMaps), and customize synchronization behavior to optimize for your\n  specific use case.\n\n## Installation\n\nLibrary:\n\n```bash\n# Using npm\nnpx jsr add @cross/kv\n\n# Using Deno\ndeno add @cross/kv\n\n# Using bun\nbunx jsr add @cross/kv\n```\n\nCommand line client `ckv`:\n\n```bash\n# Using Deno\ndeno install -frA --name ckv jsr:@cross/kv/cli\n```\n\n## API Documentation\n\n### Methods\n\n- `KV(options)` - Main class. Options are optional.\n  - `async open(filepath, createIfMissing = true, ignoreReadErrors = false)` -\n    Opens the KV store at the specified file path, creating it if it doesn't\n    exist (default behavior).\n  - `async set\u003cT\u003e(key, value)` - Stores a value associated with the given key.\n  - `async delete(key)` - Removes the key-value pair identified by the key.\n  - `async get\u003cT\u003e(key)` - Retrieves the value associated with the specified key.\n    Returns null if the key does not exist.\n  - `async *iterate\u003cT\u003e(query, limit, reverse)` - Asynchronously iterates over\n    the latest values matching the query\n  - `async listAll\u003cT\u003e(query, limit, reverse)` - Retrieves all latest values\n    matching the query as an array.\n  - `async *scan\u003cT\u003e(query, limit, reverse, ignoreReadErrors = false)` -\n    Asynchronously iterates over the transaction history (all set and delete\n    operations) for keys matching the query. Optionally recurses into subkeys\n    and fetches the associated data.\n  - `listKeys(query)` - Returns an array of all keys matching the given query.\n  - `async sync(ignoreReadErrors = false)` - Manually synchronizes the in-memory\n    index with the on-disk data store.\n  - `watch\u003cT\u003e(query, callback, recursive): void` - Registers a callback to be\n    invoked whenever a matching transaction (set or delete) is added.\n  - `unwatch\u003cT\u003e(query, callback): void` - Unregisters a previously registered\n    watch handler.\n  - `beginTransaction()` - Starts an atomic transaction, ensuring data\n    consistency for multiple operations.\n  - `async endTransaction()` - Commits all changes made within the transaction,\n    or rolls back if errors occur.\n  - `async vacuum(ignoreReadErrors = false)` - Optimizes storage by removing\n    redundant transaction history, retaining only the latest value for each key.\n  - `on(eventName, eventData)` - Subscribes to events like `sync`,\n    `watchdogError`, or `closing` to get notified of specific occurrences.\n  - `isOpen()` - Returns true if the database is open and ready for operations.\n  - `defer(promiseToHandle, [errorHandler], [timeoutMs])` - Defers the\n    resolution or rejection of a Promise until `.close()`\n  - `async close()` - Closes the KV store, ensuring resources are released.\n\n### Keys\n\n- Arrays of strings or numbers\n- First element in a key must be a string.\n- Strings must only contain alphanumeric characters, hyphens, underscores or\n  \"@\".\n\n**Examples keys**\n\n```\n[\"users\", 123]\n[\"products\", \"category\", { from: 10, to: 20 }]\n```\n\n### Values\n\nValues (or documents) are the data you store in the database. They can be any\nJavaScript primitive or a complex object containing CBOR-serializable types,\nincluding:\n\n- **Numbers:** (e.g., `12345`)\n- **Strings:** (e.g., `\"Hello, world!\"`)\n- **Booleans:** (e.g., `true`)\n- **Arrays:** (e.g., `[1, 2, 3]`)\n- **Objects:** (e.g., `{ \"name\": \"Alice\", \"age\": 30 }`)\n- **Maps:** (e.g., `new Map([[\"key1\", \"value1\"], [\"key2\", \"value2\"]])`)\n- **Sets:** (e.g., `new Set([1, 2, 3])`)\n- **Dates:** (e.g., `new Date()`)\n- **null**\n\n### Queries\n\nQueries are similar to keys but with additional support for ranges, specified as\nobjects like `{ from: 5, to: 20 }` or `{ from: \"a\", to: \"l\" }`. An empty range\n(`{}`) matches any document.\n\n**Example queries**\n\n```\n// All users\n[\"users\"]       \n// Specific user with ID 123          \n[\"users\", 123]            \n// All products in any category\n[\"products\", \"category\"]  \n// Products in category with an id up to 20\n[\"products\", \"category\", { to: 20 }] \n // Sub document \"specification\" of products in category 10 to 20\n[\"products\", \"category\", { from: 10, to: 20 }, \"specifications\"]\n// Sub-document \"author\" of any book\n[\"products\", \"book\", {}, \"author\"]\n```\n\n### Options\n\nYou can customize the behavior of the KV store using the following options when\ncreating a new KV instance:\n\n```typescript\nconst db = new KV({\n  autoSync: true, // Enable/disable automatic synchronization (default: true)\n  syncIntervalMs: 1000, // Synchronization interval in milliseconds (default: 1000)\n  ledgerCacheSize: 100, // Ledger cache size in megabytes (default: 100)\n  disableIndex: false, // Disable in-memory index for faster loading but limited functionality (default: false)\n  enableIndexCache: true, // Enable persistent index caching for faster cold starts (default: true)\n});\n```\n\nExplanations:\n\n- **autoSync** (boolean):\n  - `true` (default): The in-memory index is automatically synchronized with the\n    on-disk ledger in the background. This is recommended for multi-process\n    scenarios.\n  - `false`: Automatic synchronization is disabled. You'll need to call\n    db.sync() manually to keep the index up-to-date with other processes. This\n    might be suitable for single-process scenarios, or where you fine grained\n    control over performance.\n- **syncIntervalMs** (number): Specifies the interval (in milliseconds) between\n  automatic synchronization operations if autoSync is enabled. A shorter\n  interval provides more up-to-date data but may introduce more overhead.\n- **ledgerCacheSize** (number): Sets the maximum amount of ledger data (in\n  megabytes) to cache in memory. A larger cache can improve read performance but\n  consumes more memory. (Default `100`).\n- **disableIndex** (boolean):\n  - `false` (default): The in-memory index is enabled, allowing for efficient\n    data retrieval and complex queries.\n  - `true`: The in-memory index is disabled, resulting in faster loading times\n    but preventing the use of get, iterate, scan, and list. This is suitable\n    only when you need to append data to the ledger and don't require efficient\n    querying.\n- **enableIndexCache** (boolean):\n  - `true` (default): Enables persistent caching of the in-memory index to a\n    separate `.idx` file alongside the database. On startup, the cached index is\n    loaded from disk instead of rebuilding it from scratch, significantly\n    improving cold start performance for large databases. The cache is\n    automatically invalidated when the ledger is recreated (e.g., after vacuum\n    operations) and includes validation checks to ensure consistency.\n  - `false`: Index caching is disabled. The index is rebuilt from the ledger on\n    every startup, which may be slower for large databases but eliminates the\n    `.idx` cache file.\n\n## Concurrency\n\n`cross/kv` has a built-in mechanism for synchronizing the in-memory index with\nthe transaction ledger, allowing multiple processes to work with the same\ndatabase simultaneously.\n\nDue to the append-only design of the ledger, each process can update its\ninternal state by reading all new transactions appended since the last processed\ntransaction.\n\n### Single-Process Synchronization\n\nIn single-process scenarios, explicit synchronization is often unnecessary. You\ncan disable automatic synchronization by setting the `autoSync` option to\n`false`, eliminating automated `.sync()` calls. This can potentially improve\nperformance when only one process accesses the database.\n\n### Multi-Process Synchronisation\n\nIn multi-process scenarios, synchronization is essential for maintaining data\nconsistency. `cross/kv` offers automatic index synchronization upon each data\ninsertion and at a configurable interval (default: 1000ms). Customizing this\ninterval providing fine-grained control over the trade-off between consistency\nand performance. For strict consistency guarantees, you can manually call\n`.sync()` before reading data.\n\n```ts\nawait kv.sync(); // Ensure the most up-to-date data\nconst result = await kv.get([\"my\", \"key\"]); // Now read with confidence\n```\n\n### Monitoring Synchronization Events\n\nYou can subscribe to the `sync` event to receive notifications about\nsynchronization results and potential errors:\n\n```typescript\nconst kvStore = new KV();\nawait kvStore.open(\"db/mydatabase.db\");\n\nkvStore.on(\"sync\", (eventData) =\u003e {\n  switch (eventData.result) {\n    case \"ready\": // No new updates\n    case \"success\": // Synchronization successful, new transactions added\n    case \"ledgerInvalidated\": // Ledger recreated, database reopened and index resynchronized\n    case \"error\": // An error occurred during synchronization\n    default:\n      // Handle unexpected eventData.result values if needed\n  }\n});\n```\n\n## Changelog\n\nSee the full changelog in the docs site source:\n[docs/src/changelog.md](./docs/src/changelog.md).\n\n## Contributing\n\nContributions are welcome! Feel free to open issues or submit pull requests.\n\nThe task `deno task check` runs all tests, and is a good pre-commit check.\n`deno task check-coverage` do require `genhtml` available through the `lcov`\npackage in most distributions.\n\nFor a detailed code coverage analysis, see [COVERAGE.md](./COVERAGE.md).\n\n## **License**\n\nMIT License\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcross-org%2Fkv","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcross-org%2Fkv","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcross-org%2Fkv/lists"}