{"id":50639747,"url":"https://github.com/huxinhai/node-mmkv","last_synced_at":"2026-06-07T07:04:24.472Z","repository":{"id":362508226,"uuid":"1192380913","full_name":"huxinhai/node-mmkv","owner":"huxinhai","description":"Node-API bindings for Tencent MMKV, optimized for Node.js and Electron.","archived":false,"fork":false,"pushed_at":"2026-06-04T13:38:45.000Z","size":64,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-04T15:12:32.514Z","etag":null,"topics":["electron","key-value-store","mmkv","native-addon","node-addon-api","nodejs"],"latest_commit_sha":null,"homepage":"","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/huxinhai.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"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":null,"dco":null,"cla":null}},"created_at":"2026-03-26T06:46:51.000Z","updated_at":"2026-06-04T13:40:07.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/huxinhai/node-mmkv","commit_stats":null,"previous_names":["huxinhai/node-mmkv"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/huxinhai/node-mmkv","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/huxinhai%2Fnode-mmkv","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/huxinhai%2Fnode-mmkv/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/huxinhai%2Fnode-mmkv/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/huxinhai%2Fnode-mmkv/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/huxinhai","download_url":"https://codeload.github.com/huxinhai/node-mmkv/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/huxinhai%2Fnode-mmkv/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34011815,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-07T02:00:07.652Z","response_time":124,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"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":["electron","key-value-store","mmkv","native-addon","node-addon-api","nodejs"],"created_at":"2026-06-07T07:03:58.766Z","updated_at":"2026-06-07T07:04:24.466Z","avatar_url":"https://github.com/huxinhai.png","language":"C++","funding_links":[],"categories":[],"sub_categories":[],"readme":"# mmkv\n\n**Language:** English | [简体中文](README.zh-CN.md)\n\n`mmkv` is a Node-API native binding for [Tencent MMKV](https://github.com/Tencent/MMKV). It provides high-performance, persistent key-value storage for Node.js and Electron applications by wrapping the upstream MMKV core that is vendored in this repository under `MMKV/`.\n\nThis project is focused on practical local storage APIs for desktop runtime use: typed values, binary buffers, encryption keys, store maintenance, and backup/restore.\n\n## Status\n\n- Package name: `mmkv`\n- Runtime: Node.js 20+\n- Package manager: pnpm 10.12.4\n- Native layer: Node-API through `node-addon-api`\n- Native output: `build/Release/mmkv.node`\n- Current CI targets: `darwin-arm64`, `darwin-x64`, `windows-x64`\n- TypeScript declarations: [`index.d.ts`](index.d.ts)\n- Package visibility: public, with no `private` flag\n- npm publishing: automated publishing is not configured yet\n\n## Features\n\n- Boolean values\n- `int32`, `uint32`, `int64`, and `uint64`\n- `float` and `double`\n- `string`\n- Node.js `Buffer`\n- Multiple MMKV stores by id\n- `defaultMMKV`\n- Per-store options: `rootPath`, `multiProcess`, `readOnly`, `expectedCapacity`, `cryptKey`, and `aes256`\n- Encryption key rotation and removal with `reKey`\n- Key lookup, listing, deletion, counts, and size inspection\n- `clearAll`, `trim`, `sync`, `lock`, `unlock`, `tryLock`, and `close`\n- Single-store and all-store backup/restore\n\nThe binding does not expose every upstream MMKV capability yet. It prioritizes the API surface currently used and tested for Node.js and Electron.\n\n## Requirements\n\n- Node.js 20 or newer\n- pnpm 10 or newer\n- Python 3\n- A C++20-capable native build toolchain\n- `git` with submodule support\n\nOn macOS, install Xcode Command Line Tools. On Windows, use a Visual Studio/MSVC build environment that works with `node-gyp`.\n\n## Build\n\nInitialize the MMKV submodule if needed, then install, build, and test:\n\n```bash\ngit submodule update --init --recursive\npnpm install\npnpm build\npnpm test\n```\n\n`pnpm test` runs Node's test runner with `--expose-gc`, because the smoke suite includes memory regression checks.\n\nOn Apple Silicon, keep the terminal architecture and Node.js architecture aligned with the binary you want to build:\n\n```bash\narch -arm64 zsh\nnode -p \"process.arch\"\npnpm install\npnpm build\npnpm test\n```\n\nTo verify the Intel/Rosetta build on Apple Silicon:\n\n```bash\narch -x86_64 zsh\nnode -p \"process.arch\"\npnpm install\npnpm build\npnpm test\n```\n\nUse the `darwin-arm64` build for native Apple Silicon runtimes and the `darwin-x64` build for Intel Mac or x64 Electron under Rosetta.\n\n## Quick Start\n\n```js\nconst { MMKV } = require(\"mmkv\");\n\nMMKV.initialize(\"./.mmkv\");\n\nconst kv = new MMKV(\"app\");\n\nkv.setBool(\"ready\", true);\nkv.setInt32(\"count\", 42);\nkv.setUInt64(\"max\", 18446744073709551615n);\nkv.setFloat(\"ratio\", 1.25);\nkv.setDouble(\"price\", 19.99);\nkv.setString(\"name\", \"demo\");\nkv.setBuffer(\"payload\", Buffer.from([1, 2, 3]));\n\nconsole.log(kv.getBool(\"ready\"));\nconsole.log(kv.getInt32(\"count\"));\nconsole.log(kv.getUInt64(\"max\"));\nconsole.log(kv.getFloat(\"ratio\"));\nconsole.log(kv.getDouble(\"price\"));\nconsole.log(kv.getString(\"name\"));\nconsole.log(kv.getBuffer(\"payload\"));\n\nkv.close();\nMMKV.onExit();\n```\n\nCall `MMKV.initialize(rootDir)` before opening stores that rely on the global MMKV root directory. You can also pass `rootPath` per store.\n\n## Opening Stores\n\n```js\nconst { MMKV } = require(\"mmkv\");\n\nMMKV.initialize(\"/tmp/mmkv-root\", 4);\n\nconst kv = new MMKV(\"user-cache\", {\n  rootPath: \"/tmp/mmkv-root\",\n  multiProcess: false,\n  readOnly: false,\n  expectedCapacity: 1024 * 1024,\n});\n\nconst defaultStore = MMKV.defaultMMKV({\n  rootPath: \"/tmp/mmkv-root\",\n});\n```\n\nThe second argument to `MMKV.initialize` is the numeric upstream MMKV log level. Passing `4` disables MMKV logs.\n\n## Values\n\n```js\nkv.setBool(\"flag\", true);\nkv.getBool(\"flag\", false);\n\nkv.setInt32(\"signed\", -1);\nkv.getInt32(\"signed\", 0);\n\nkv.setUInt32(\"unsigned\", 4294967295);\nkv.getUInt32(\"unsigned\", 0);\n\nkv.setInt64(\"largeSigned\", -9007199254740991n);\nkv.getInt64(\"largeSigned\", 0n);\n\nkv.setUInt64(\"largeUnsigned\", 18446744073709551615n);\nkv.getUInt64(\"largeUnsigned\", 0n);\n\nkv.setFloat(\"floatValue\", 1.25);\nkv.getFloat(\"floatValue\", 0);\n\nkv.setDouble(\"doubleValue\", Math.PI);\nkv.getDouble(\"doubleValue\", 0);\n\nkv.setString(\"message\", \"hello\");\nkv.getString(\"message\");\n\nkv.setBuffer(\"bytes\", Buffer.from([0xde, 0xad, 0xbe, 0xef]));\nkv.getBuffer(\"bytes\");\n```\n\nUse `bigint` for 64-bit integer values outside JavaScript's safe integer range. `getInt64` and `getUInt64` always return `bigint`.\n\n`getString` and `getBuffer` return `null` when the value is not found.\n\n## Keys and Maintenance\n\n```js\nkv.containsKey(\"message\");\nkv.allKeys();\nkv.count();\n\nkv.removeValueForKey(\"message\");\nkv.removeValuesForKeys([\"flag\", \"bytes\"]);\n\nkv.totalSize();\nkv.actualSize();\n\nkv.sync();\nkv.sync(true);\nkv.trim();\nkv.clearAll();\nkv.clearAll(true);\n\nif (kv.tryLock()) {\n  try {\n    // protected work\n  } finally {\n    kv.unlock();\n  }\n}\n\nkv.close();\n```\n\nOnce `close()` has been called, instance methods throw because the native MMKV handle is closed.\n\n## Encryption\n\n```js\nconst secure = new MMKV(\"secure\", {\n  rootPath: \"/tmp/mmkv-root\",\n  cryptKey: \"initial-secret\",\n  aes256: true,\n});\n\nsecure.setString(\"token\", \"abc123\");\nconsole.log(secure.cryptKey());\n\nsecure.reKey(\"rotated-secret\", true);\nsecure.reKey(null);\nsecure.close();\n```\n\n`cryptKey()` reports the key known to this JavaScript wrapper instance. It does not read or reveal a key from MMKV storage.\n\n## Backup and Restore\n\n```js\nconst { MMKV } = require(\"mmkv\");\n\nMMKV.initialize(\"/tmp/mmkv-root\");\n\nconst kv = new MMKV(\"session\");\nkv.setString(\"token\", \"hello\");\nkv.sync();\nkv.close();\n\nMMKV.backupOneToDirectory(\"session\", \"/tmp/mmkv-backup\", \"/tmp/mmkv-root\");\nMMKV.restoreOneFromDirectory(\"session\", \"/tmp/mmkv-backup\", \"/tmp/mmkv-restore\");\n\nMMKV.backupAllToDirectory(\"/tmp/mmkv-backup-all\", \"/tmp/mmkv-root\");\nMMKV.restoreAllFromDirectory(\"/tmp/mmkv-backup-all\", \"/tmp/mmkv-restore-all\");\n```\n\n`backupOneToDirectory` and `restoreOneFromDirectory` return booleans. `backupAllToDirectory` and `restoreAllFromDirectory` return the number of stores processed.\n\n## TypeScript\n\nType declarations are included in [`index.d.ts`](index.d.ts). The main runtime exports are:\n\n```ts\nimport { MMKV, version } from \"mmkv\";\n```\n\nThe public API includes:\n\n- Static: `initialize`, `onExit`, `version`, `defaultMMKV`, `backupOneToDirectory`, `restoreOneFromDirectory`, `backupAllToDirectory`, `restoreAllFromDirectory`\n- Values: `setBool/getBool`, `setInt32/getInt32`, `setUInt32/getUInt32`, `setInt64/getInt64`, `setUInt64/getUInt64`, `setFloat/getFloat`, `setDouble/getDouble`, `setString/getString`, `setBuffer/getBuffer`\n- Keys: `containsKey`, `removeValueForKey`, `removeValuesForKeys`, `allKeys`, `count`\n- Maintenance: `totalSize`, `actualSize`, `clearAll`, `trim`, `sync`, `lock`, `unlock`, `tryLock`, `reKey`, `cryptKey`, `close`\n\n## Electron Notes\n\n- Prefer loading the native module in the main process.\n- Match the `.node` binary architecture to the Electron runtime architecture.\n- Use `darwin-arm64` for native Apple Silicon Electron.\n- Use `darwin-x64` for Intel Mac or x64 Electron under Rosetta.\n- Use `windows-x64` for 64-bit Windows Electron.\n- Do not load an arm64 `.node` binary into an x64 Electron process, or the reverse.\n- Use a dedicated `rootPath` per application.\n\nMMKV data is isolated by `rootPath` and store id. Two applications will not overwrite each other if they use different roots. Under the same root, different ids map to different stores. A conflict happens when two runtimes use the same `rootPath` and the same id for incompatible data.\n\n## CI Binary Bundles\n\nThe repository includes [`build-binaries.yml`](.github/workflows/build-binaries.yml). It runs on:\n\n- Pushes to `main`\n- Pull requests\n- Manual `workflow_dispatch`\n- Published GitHub Releases\n\nThe workflow builds and tests each target, strips the native binary when possible, then packages:\n\n- `darwin-arm64`\n- `darwin-x64`\n- `windows-x64`\n\nRelease builds upload `dist/mmkv-v\u003cversion\u003e-\u003ctarget\u003e.tar.gz` archives as release assets.\n\n## Project Layout\n\n```text\nsrc/\n  core/\n    node_mmkv_binding.h\n    node_mmkv_core.cpp\n  helpers/\n    config_parser.*\n    value_utils.*\n  bindings/\n    module_init.cpp\n    static/\n      admin.cpp\n      backup.cpp\n    instance/\n      numbers.cpp\n      strings.cpp\n      buffers.cpp\n      keys.cpp\n      maintenance.cpp\nMMKV/\n  Upstream Tencent MMKV source tree\nbinding.gyp\nindex.d.ts\ntest/smoke.test.ts\n```\n\nSee [`DEVELOPMENT.md`](DEVELOPMENT.md) for local development notes, especially macOS architecture handling.\n\n## Tests\n\nThe smoke test suite in [`test/smoke.test.ts`](test/smoke.test.ts) covers:\n\n- Basic typed reads and writes\n- `defaultMMKV`\n- Encrypted storage and `reKey`\n- Single-store backup/restore\n- All-store backup/restore\n- Locking and maintenance methods\n- Repeated open/write/clear/close cycles with memory snapshots\n\nRun:\n\n```bash\npnpm test\n```\n\n## Current Limits\n\n- No automated npm publish flow yet.\n- No install-time prebuilt binary downloader yet.\n- Linux is not part of the package `os` list or CI target matrix.\n- The binding covers common Node.js and Electron storage needs, but not the full upstream MMKV API.\n- Native binaries are stripped for size, but the project avoids high-risk compression or obfuscation steps such as UPX to preserve Electron and macOS loading compatibility.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhuxinhai%2Fnode-mmkv","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhuxinhai%2Fnode-mmkv","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhuxinhai%2Fnode-mmkv/lists"}