{"id":16629,"library":"jdb","title":"JDB File-Append-Only Database","description":"JDB is a lightweight, file-append-only, in-memory, non-blocking I/O database inspired by NeDB. It allows users to manipulate data directly using standard JavaScript code, eliminating the need for a separate query language. The current stable version is 0.5.5, indicating a relatively mature but perhaps slower-paced development cycle without explicit release cadence information. Key differentiators include its lightweight core (approx. 200 lines), direct JavaScript data manipulation, promise support, and both standalone server and in-application library modes. It operates by appending JavaScript commands to a file, which are then re-executed on startup to reconstruct the database's in-memory state. Periodically, the database file can be compacted into a single JSON object to optimize storage and startup time.","status":"active","version":"0.5.5","language":"javascript","source_language":"en","source_url":"https://github.com/ysmood/jdb","tags":["javascript","database"],"install":[{"cmd":"npm install jdb","lang":"bash","label":"npm"},{"cmd":"yarn add jdb","lang":"bash","label":"yarn"},{"cmd":"pnpm add jdb","lang":"bash","label":"pnpm"}],"dependencies":[],"imports":[{"note":"The `jdb` package exports a factory function that must be immediately invoked `()` to get the database instance. It is primarily a CommonJS module.","wrong":"import jdb from 'jdb';\nconst jdb = require('jdb');","symbol":"jdb","correct":"const jdb = require('jdb')();"},{"note":"The `init` method initializes the database and returns a Promise by default (since `promise` option defaults to `true`). Callback-style is also supported but Promise is preferred for modern async/await patterns.","wrong":"jdb.init((err) => { /* ... */ });","symbol":"init","correct":"await jdb.init();"},{"note":"The `exec` method takes an options object or data + command function. The `command` function is executed in an isolated scope, requiring all necessary data to be passed via the `data` option.","wrong":"jdb.exec((db) => { db.doc.myKey = outerScopeVar; });","symbol":"exec","correct":"await jdb.exec({ data: someData, command: (db, data) => db.doc.myKey = data });"}],"quickstart":{"code":"const jdb = require('jdb')();\nconst path = require('path');\nconst fs = require('fs');\n\nconst dbFilePath = path.join(__dirname, 'temp.jdb');\n\nconst some_data = {\n    \"name\": {\n        \"first\": \"Yad\",\n        \"last\": \"Smood\"\n    },\n    \"fav_color\": \"blue\",\n    \"languages\": [\n        { \"name\": \"Chinese\", \"level\": 10 },\n        { \"name\": \"English\", \"level\": 8, \"preferred\": true },\n        { \"name\": \"Japanese\", \"level\": 6 }\n    ],\n    \"height\": 180,\n    \"weight\": 68\n};\n\nasync function runQuickstart() {\n    // Clean up previous runs\n    if (fs.existsSync(dbFilePath)) {\n        fs.unlinkSync(dbFilePath);\n    }\n\n    try {\n        // Initialize JDB with a specific file path\n        await jdb.init({ dbPath: dbFilePath });\n        console.log('Database initialized at:', dbFilePath);\n\n        // Set data using exec with callback (converted to promise for sequential execution)\n        await new Promise((resolve, reject) => {\n            jdb.exec(\n                {\n                    data: some_data,\n                    command: (jdbInstance, data) => {\n                        jdbInstance.doc.ys = data;\n                        jdbInstance.save('saved_data'); // Save with a return value\n                    },\n                    callback: (err, result) => {\n                        if (err) return reject(err);\n                        console.log('Exec with callback result:', result); // Expected: 'saved_data'\n                        resolve(result);\n                    }\n                }\n            );\n        });\n\n        // Simple way to save data using exec with promise\n        await jdb.exec(some_data, (jdbInstance, data) => {\n            jdbInstance.doc.arr = data.languages.map((el) => el.name);\n            jdbInstance.save(); // Default save returns undefined on success\n        });\n        console.log('Second data save completed.');\n\n        // Get the value after operations complete from the current instance\n        console.log('Current instance: jdb.doc.ys.name:', jdb.doc.ys.name); \n        console.log('Current instance: jdb.doc.arr:', jdb.doc.arr);\n\n        // Simulate restart by creating a new JDB instance and initializing from the same file\n        const jdb2 = require('jdb')();\n        await jdb2.init({ dbPath: dbFilePath });\n        console.log('\\n--- After simulated restart ---');\n        console.log('New instance: jdb2.doc.ys.name:', jdb2.doc.ys.name);\n        console.log('New instance: jdb2.doc.arr:', jdb2.doc.arr);\n\n    } catch (err) {\n        console.error('An error occurred:', err);\n    } finally {\n        // Clean up the database file\n        if (fs.existsSync(dbFilePath)) {\n            fs.unlinkSync(dbFilePath);\n            console.log('\\nCleaned up database file:', dbFilePath);\n        }\n    }\n}\n\nrunQuickstart();","lang":"javascript","description":"This quickstart demonstrates initializing a JDB instance, saving complex JavaScript objects using both callback and promise-based `exec` methods, accessing the saved data directly from the in-memory document, and finally simulating a restart to confirm data persistence by re-initializing from the saved file. It also includes cleanup of the temporary database file."},"warnings":[{"fix":"Only use JDB with database files from trusted sources and ensure strict file system permissions for database files. Avoid using JDB in multi-tenant environments where users can submit arbitrary JavaScript code for data manipulation without stringent validation.","message":"JDB's core mechanism involves persisting database operations as executable JavaScript code, which is re-evaluated on startup. This design inherently means that if the database file (.jdb) is tampered with or contains untrusted code, arbitrary code execution can occur in the Node.js process. This poses a significant security risk for applications that might receive database files from untrusted sources or operate in environments where the file system is not secured.","severity":"breaking","affected_versions":">=0.1.0"},{"fix":"Pass any necessary external data into the `exec` call via the `data` option, and access it within the command function through the `data` argument: `jdb.exec({ data: myExternalData, command: (jdb, receivedData) => { jdb.doc.myKey = receivedData; jdb.save(); } });`","message":"When defining the `command` function for `jdb.exec`, direct access to variables from the outer scope (closure) is not permitted. The command function is serialized and executed in its own isolated context, receiving only `jdbInstance` and `data` arguments.","severity":"gotcha","affected_versions":">=0.1.0"},{"fix":"Regularly use `jdb.compactDBFile()` (or enable `compactDBFile: true` in `init` options) to reduce the number of commands that need to be replayed. Consider alternative database solutions if extremely fast startup for very large, highly mutable datasets is a critical requirement.","message":"For databases with a very large number of operations (many `jdb.exec` calls), startup time can be significantly affected. JDB rebuilds its in-memory state by re-executing every JavaScript command ever appended to the database file. While compaction helps reduce file size, the entire command history still needs to be replayed.","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":"Pass the required data via the `data` property of the `exec` options object and access it as the second argument to your command function: `jdb.exec({ data: myValue, command: (db, receivedValue) => { db.doc.someKey = receivedValue; db.save(); } });`","cause":"Attempting to access an outer-scope variable directly within the `command` function passed to `jdb.exec`. The command function executes in an isolated scope.","error":"ReferenceError: [variable_name] is not defined at command (eval at <anonymous> (...))"},{"fix":"Ensure you invoke the required module by adding `()` after the `require` call: `const jdb = require('jdb')();`","cause":"The `jdb` package exports a factory function, not a direct database instance. It must be called to instantiate the database.","error":"TypeError: require(...) is not a function"}],"ecosystem":"npm"}