{"id":17290,"library":"lum_lokijs","title":"LokiJS: In-Memory Document Database","description":"LokiJS is a fast, embeddable, document-oriented NoSQL database written entirely in JavaScript. It operates in-memory, making it suitable for performance-critical applications like client-side session stores, embedded databases in Electron or Node-WebKit apps, or mobile applications using frameworks like Nativescript and Cordova. It features collections with unique and binary indexes, dynamic views, a Changes API for synchronization, and supports joins. Persistence is handled through a pluggable adapter system, with built-in adapters for Node.js file system, browser IndexedDB, and localStorage. While the last published version on npm is 1.5.12 (last updated around 2019-2020), the project has seen minimal activity and is largely considered unmaintained, with its official successor being LokiDB. Users should be aware of its unmaintained status and consider the successor or other alternatives for new projects.","status":"abandoned","version":"1.5.11","language":"javascript","source_language":"en","source_url":"https://github.com/techfort/LokiJS","tags":["javascript","document-oriented","mmdb","json","nosql","lokijs","in-memory"],"install":[{"cmd":"npm install lum_lokijs","lang":"bash","label":"npm"},{"cmd":"yarn add lum_lokijs","lang":"bash","label":"yarn"},{"cmd":"pnpm add lum_lokijs","lang":"bash","label":"pnpm"}],"dependencies":[],"imports":[{"note":"LokiJS typically uses a default export for the main `Loki` class. CommonJS `require` is the most historically common usage pattern for this library. For ESM, you often need to import the default.","wrong":"import { Loki } from 'lokijs';","symbol":"Loki","correct":"import Loki from 'lokijs';\n// Or for CommonJS:\nconst Loki = require('lokijs');"},{"note":"Persistence adapters like LokiIndexedAdapter are imported from specific sub-paths within the `lokijs/src` directory, not directly from the main package export.","wrong":"import { LokiIndexedAdapter } from 'lokijs';","symbol":"LokiIndexedAdapter","correct":"import LokiIndexedAdapter from 'lokijs/src/loki-indexed-adapter';\n// Or for CommonJS:\nconst LokiIndexedAdapter = require('lokijs/src/loki-indexed-adapter');"},{"note":"The `Collection` class itself is typically not directly imported, but instances are created and returned by methods on the `Loki` database instance, such as `db.addCollection()`.","symbol":"Collection","correct":"const users = db.addCollection('users');\n// (Collection class is usually instantiated via db.addCollection, not directly imported)"}],"quickstart":{"code":"const Loki = require('lokijs');\nconst LokiIndexedAdapter = require('lokijs/src/loki-indexed-adapter');\n\nasync function initializeDatabase() {\n  const adapter = new LokiIndexedAdapter('my-loki-app');\n  const db = new Loki('my-database.db', {\n    adapter: adapter,\n    autosave: true,\n    autosaveInterval: 4000 // Save every 4 seconds\n  });\n\n  // Load the database from persistence, or create if it doesn't exist\n  await new Promise((resolve, reject) => {\n    db.loadDatabase({}, (err) => {\n      if (err) {\n        console.error('Error loading database:', err);\n        reject(err);\n      } else {\n        console.log('Database loaded or created.');\n        resolve();\n      }\n    });\n  });\n\n  let users = db.getCollection('users');\n  if (!users) {\n    users = db.addCollection('users', { unique: ['email'], autoupdate: true });\n    console.log('\"users\" collection created.');\n  }\n\n  // Insert some data if the collection is empty\n  if (users.count() === 0) {\n    users.insert({ name: 'Alice', email: 'alice@example.com', age: 30 });\n    users.insert({ name: 'Bob', email: 'bob@example.com', age: 24 });\n    users.insert({ name: 'Charlie', email: 'charlie@example.com', age: 35 });\n    console.log('Initial data inserted.');\n  }\n\n  // Find and update a document\n  let bob = users.findOne({ name: 'Bob' });\n  if (bob) {\n    bob.age = 25;\n    users.update(bob); // Explicit update might be needed for certain changes like array mutations\n    console.log('Bob updated:', users.findOne({ name: 'Bob' }));\n  }\n\n  // Query data\n  const youngUsers = users.find({ age: { '$lt': 30 } });\n  console.log('Users under 30:', youngUsers);\n\n  // Save changes explicitly (autosave also does this)\n  await new Promise((resolve, reject) => {\n    db.saveDatabase((err) => {\n      if (err) reject(err); else resolve();\n    });\n  });\n  console.log('Database saved.');\n\n  return db;\n}\n\ninitializeDatabase().catch(console.error);\n","lang":"javascript","description":"This quickstart initializes a LokiJS database with IndexedDB persistence, creates a collection, inserts and updates documents, and demonstrates a basic query. It highlights asynchronous database loading/saving and explicit updates."},"warnings":[{"fix":"For new projects, evaluate migrating to `@lokidb/loki` or other actively maintained in-memory databases like NeDB (though also unmaintained) or Dexie.js. For existing projects, be aware of the lack of updates and potential issues.","message":"The original LokiJS project (`techfort/LokiJS`) is largely unmaintained, with its last npm update being around 5 years ago for version 1.5.12. Users are strongly advised to consider `LokiDB` (`@lokidb/loki`), which is explicitly stated as its official successor and is actively maintained with TypeScript support and modern features. Continuing with LokiJS for new projects may lead to encountering unaddressed bugs or security vulnerabilities.","severity":"breaking","affected_versions":">=1.3"},{"fix":"Always initialize `Loki` with an `adapter` and `autosave: true`, or ensure you manually call `db.loadDatabase()` at startup and `db.saveDatabase()` before shutdown or critical data changes. For browsers, `LokiIndexedAdapter` is generally preferred over `LokiLocalStorageAdapter` for larger datasets due to storage limits.","message":"LokiJS is an in-memory database, meaning all data resides in RAM. Without a persistence adapter (like `LokiFsAdapter` for Node.js or `LokiIndexedAdapter` for browsers), all data will be lost when the application process terminates or the browser tab closes. Implementing proper persistence and handling `loadDatabase` and `saveDatabase` (or using `autosave`) is crucial.","severity":"gotcha","affected_versions":">=1.0"},{"fix":"For changes involving array mutations (e.g., `document.array.push(item)`) or deep nesting, explicitly call `collection.update(document)` after modification to ensure the database registers the change and updates its internal indexes and persistence state.","message":"Changes made directly to properties of objects retrieved from a collection are usually tracked by LokiJS if `autoupdate` is enabled on the collection. However, mutations to arrays or nested objects *within* a document might not always be automatically detected, requiring an explicit `collection.update(document)` call to ensure persistence and index updates.","severity":"gotcha","affected_versions":">=1.0"},{"fix":"When using ESM, import `Loki` as a default export (`import Loki from 'lokijs';`). For adapters, ensure correct sub-path imports (`import LokiIndexedAdapter from 'lokijs/src/loki-indexed-adapter';`). If working in a pure ESM environment, dynamic `import()` might be needed for some CJS-only modules if direct transpilation fails. If using TypeScript, ensure `esModuleInterop` is enabled in `tsconfig.json`.","message":"LokiJS primarily uses a CommonJS module structure. Importing it in modern Node.js or browser environments that default to ES Modules (`import`) can lead to unexpected behavior or require specific transpilation or configuration. The main `Loki` class is typically a default export, while adapters are often in sub-paths.","severity":"gotcha","affected_versions":">=1.0"}],"env_vars":null,"last_verified":"2026-04-22T00:00:00.000Z","next_check":"2026-07-21T00:00:00.000Z","problems":[{"fix":"Use `import Loki from 'lokijs';` for ESM or `const Loki = require('lokijs');` for CommonJS. Do not use `import { Loki } from 'lokijs';`.","cause":"Attempting to instantiate `Loki` using a named import or incorrect CommonJS require pattern when the package primarily uses a default export, especially in an ESM context.","error":"TypeError: Loki is not a constructor"},{"fix":"Ensure the path to the adapter is correct and matches the file structure of the installed `lokijs` package, typically `lokijs/src/loki-indexed-adapter` (or `loki-fs-adapter`, etc.).","cause":"Incorrect path for importing persistence adapters, or the adapter file is missing/mislocated.","error":"Error: Cannot find module 'lokijs/src/loki-indexed-adapter'"},{"fix":"Initialize `Loki` with an `adapter` (e.g., `new LokiIndexedAdapter()`) and ensure `db.loadDatabase()` is called with a callback to handle loading the data before interacting with collections. For automatic saving, set `autosave: true` and `autosaveInterval` during database instantiation.","cause":"Persistence adapter was not correctly configured or `loadDatabase` was not called, leading to data being stored only in-memory without saving or loading from disk/storage.","error":"Database not loaded after initialization / Data disappears on refresh."},{"fix":"Consider using `serializationMethod: 'destructured'` and `destructureDelimiter` options when initializing `Loki` for databases with large documents to mitigate serialization overhead. Optimize queries to be more specific, utilize indexes, or consider breaking down very large operations. Upgrade Node.js if applicable.","cause":"Potentially caused by large datasets combined with complex queries, or issues related to recursive operations within the library's internal mechanisms, especially on older Node.js versions or less performant environments. This can also happen with very large documents being saved/loaded, particularly with default serialization methods.","error":"RangeError: Maximum call stack size exceeded (V8-specific)"}],"ecosystem":"npm","meta_description":null}