{"id":28862669,"url":"https://github.com/acoyfellow/jotdb","last_synced_at":"2026-02-28T08:36:43.794Z","repository":{"id":294207557,"uuid":"985794948","full_name":"acoyfellow/JotDB","owner":"acoyfellow","description":"A fast, schema-optional key-value database for Cloudflare Durable Objects. JotDB combines NoSQL flexibility with Zod-powered validation and type safety—perfect for internal tools, APIs, and real-time apps at the edge.","archived":false,"fork":false,"pushed_at":"2025-08-10T19:49:42.000Z","size":115,"stargazers_count":4,"open_issues_count":1,"forks_count":1,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-11-06T15:15:52.527Z","etag":null,"topics":["cloudflare","cloudflare-durable-objects","cloudflare-workers","database-design","key-value"],"latest_commit_sha":null,"homepage":"https://www.npmjs.com/package/jotdb","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/acoyfellow.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}},"created_at":"2025-05-18T14:45:03.000Z","updated_at":"2025-10-06T13:22:54.000Z","dependencies_parsed_at":"2025-05-19T11:36:22.577Z","dependency_job_id":"40478430-86d1-425d-b41e-08cef30981c6","html_url":"https://github.com/acoyfellow/JotDB","commit_stats":null,"previous_names":["acoyfellow/jotdb"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/acoyfellow/JotDB","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/acoyfellow%2FJotDB","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/acoyfellow%2FJotDB/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/acoyfellow%2FJotDB/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/acoyfellow%2FJotDB/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/acoyfellow","download_url":"https://codeload.github.com/acoyfellow/JotDB/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/acoyfellow%2FJotDB/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29929018,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-27T19:37:42.220Z","status":"online","status_checked_at":"2026-02-28T02:00:07.010Z","response_time":90,"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":["cloudflare","cloudflare-durable-objects","cloudflare-workers","database-design","key-value"],"created_at":"2025-06-20T06:31:05.552Z","updated_at":"2026-02-28T08:36:43.775Z","avatar_url":"https://github.com/acoyfellow.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# JotDB\n\n[![Deploy to Cloudflare](https://deploy.workers.cloudflare.com/button)](https://deploy.workers.cloudflare.com/?url=https://github.com/acoyfellow/jotdb)\n\nA lightweight, schema-less database built on Cloudflare Durable Objects. Think of it as Firestore's security rules, but with Zod validation built-in. Perfect for both internal and external APIs, with automatic type safety and validation.\n\n\u003e **Cloudflare Products**: JotDB works with any Cloudflare product that supports Durable Objects:\n\u003e - Cloudflare Workers\n\u003e - Cloudflare Pages (with Functions)\n\u003e - Cloudflare Workflows\n\u003e - Cloudflare Queues\n\u003e - Cloudflare Cron Triggers\n\n## Why JotDB?\n\nJotDB combines the best of both worlds: the simplicity of NoSQL with the safety of schema validation. Here's what makes it special:\n\n- **Built-in Type Safety**: Automatic Zod validation ensures your data is always in the right shape\n- **Edge-Native**: Runs directly on Cloudflare's edge network, with sub-millisecond latency\n- **RPC-First**: Direct method calls instead of HTTP endpoints (though you can easily wrap it in HTTP)\n- **Durable Storage**: Built on Durable Objects for reliable, consistent storage\n- **Zero Setup**: No database configuration, no connection strings, just instantiate and go\n- **Perfect for APIs**: Use it as an internal database or wrap it with auth for external APIs\n- **Real-time Ready**: Durable Objects provide strong consistency guarantees\n\nPerfect for:\n- Quick prototypes that need data validation\n- Small to medium applications that need reliable storage\n- Serverless environments where you want type safety\n- Real-time data storage with strong consistency\n- Collaborative applications that need data validation\n- APIs that need both flexibility and safety\n\n## Design Patterns\n\nJotDB uses Cloudflare Durable Objects under the hood, which means you can organize your data in several ways:\n\n1. **Global Store**: Use a single instance for your entire application\n   ```typescript\n   const db = env.JOTDB.get(env.JOTDB.idFromName(\"global\"));\n   ```\n\n2. **Per-User Store**: Create a separate instance for each user\n   ```typescript\n   const userDb = env.JOTDB.get(env.JOTDB.idFromName(`user:${userId}`));\n   ```\n\n3. **Per-Event Store**: Create temporary stores for events or sessions\n   ```typescript\n   const eventDb = env.JOTDB.get(env.JOTDB.idFromName(`event:${eventId}`));\n   ```\n\nEach instance is isolated and can have its own schema and options. This follows the Actor Model pattern, where each instance is an independent actor that manages its own state.\n\n## Installation\n\n```bash\n# Using npm\nnpm install jotdb\n\n# Using yarn\nyarn add jotdb\n\n# Using pnpm\npnpm add jotdb\n```\n\n### Configure wrangler.jsonc\n\n```jsonc\n{\n  \"durable_objects\": {\n    \"bindings\": [\n      {\n        \"name\": \"JOTDB\",\n        \"class_name\": \"JotDB\"\n      }\n    ]\n  }\n}\n```\n\n## Full Example\n\n```typescript\nimport { JotDB } from 'jotdb';\n\nexport interface Env {\n  JOTDB: DurableObjectNamespace;\n}\n\nexport default {\n  async fetch(request: Request, env: Env) {\n    // Initialize the database\n    const jotId = env.JOTDB.idFromName(\"my-db\");\n    const db = env.JOTDB.get(jotId);\n\n    // Example operations\n    await db.set(\"user:123\", { name: \"John\", age: 30 });\n    const user = await db.get(\"user:123\");\n    await db.delete(\"user:123\");\n\n    // Return the result\n    return new Response(JSON.stringify({ user }), {\n      headers: { 'Content-Type': 'application/json' }\n    });\n  }\n};\n```\n\n## API Reference\n\n| Method | Description | Parameters | Returns |\n|--------|-------------|------------|---------|\n| `set(key, value)` | Store a value | `key: string`, `value: any` | `Promise\u003cvoid\u003e` |\n| `get(key)` | Retrieve a value | `key: string` | `Promise\u003cany\u003e` |\n| `delete(key)` | Remove a value | `key: string` | `Promise\u003cvoid\u003e` |\n| `clear()` | Remove all values | none | `Promise\u003cvoid\u003e` |\n| `keys()` | Get all keys | none | `Promise\u003cstring[]\u003e` |\n| `has(key)` | Check if key exists | `key: string` | `Promise\u003cboolean\u003e` |\n| `getAll()` | Get all data | none | `Promise\u003cRecord\u003cstring, unknown\u003e \\| unknown[]\u003e` |\n| `setAll(objOrArr)` | Set all data at once | `objOrArr: Record\u003cstring, unknown\u003e \\| unknown[]` | `Promise\u003cvoid\u003e` |\n| `push(item)` | Add item to array | `item: unknown` | `Promise\u003cvoid\u003e` |\n| `getSchema()` | Get current schema | none | `Promise\u003cSchemaDefinition\u003e` |\n| `setSchema(schema)` | Set data schema | `schema: SchemaDefinition` | `Promise\u003cvoid\u003e` |\n| `getOptions()` | Get current options | none | `Promise\u003cJotDBOptions\u003e` |\n| `setOptions(opts)` | Set database options | `opts: Partial\u003cJotDBOptions\u003e` | `Promise\u003cvoid\u003e` |\n| `getAuditLog()` | Get audit log entries | none | `Promise\u003cAuditLogEntry[]\u003e` |\n| `clearAuditLog()` | Clear audit log | none | `Promise\u003cvoid\u003e` |\n\n### Options\n\n```typescript\ninterface JotDBOptions {\n  autoStrip: boolean;  // Automatically strip unknown fields\n  readOnly: boolean;   // Enable read-only mode\n}\n```\n\n### Schema Types\n\n```typescript\ntype SchemaType = \"string\" | \"number\" | \"boolean\" | \"email\" | \"array\" | \"object\" | \"any\";\n```\n\n## License\n\nMIT License - feel free to use this in your own projects!\n\n## Contributing\n\nContributions are welcome! Please feel free to submit a Pull Request. For major changes, please open an issue first to discuss what you would like to change.\n\n1. Fork the repository\n2. Create your feature branch (`git checkout -b feature/amazing-feature`)\n3. Commit your changes (`git commit -m 'Add some amazing feature'`)\n4. Push to the branch (`git push origin feature/amazing-feature`)\n5. Open a Pull Request\n\n## Testing\n\nCurrently, testing is done manually in production. We're working on adding a comprehensive test suite. For now, you can test the functionality by:\n\n1. Deploying to Cloudflare Workers\n2. Using the example endpoints\n3. Verifying data persistence","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Facoyfellow%2Fjotdb","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Facoyfellow%2Fjotdb","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Facoyfellow%2Fjotdb/lists"}