MindooDB: End-to-End Encrypted Offline-First Database
MindooDB is an end-to-end encrypted, offline-first sync database designed for collaborative applications. It uniquely ensures that encryption keys never leave client devices, meaning servers only ever process and store ciphertext, providing a robust security model against server compromises and data breaches. Built on Automerge CRDTs, it offers real-time collaboration with automatic conflict resolution, tamperproof history, and fine-grained access control through named encryption keys. It functions by syncing content-addressed encrypted blobs, supporting peer-to-peer, client-server, or hybrid synchronization. The package is currently in alpha (`v0.0.17`), indicating active development but with APIs subject to change and it is not yet recommended for production use. Release cadence is irregular during this early development phase. Its key differentiator is the client-side encryption, allowing data control to remain solely with the end-users.
Common errors
-
ReferenceError: navigator is not defined
cause Attempting to use the browser-specific build of MindooDB (e.g., `mindoodb/browser`) in a Node.js environment, which lacks browser globals like `navigator`.fixFor Node.js, ensure you import from the main package: `import { MindooDB } from 'mindoodb';`. For web browsers, explicitly import from `mindoodb/browser`. -
Error: Cannot find module 'react-native-automerge-generated'
cause A required peer dependency, specifically `react-native-automerge-generated` for React Native environments, is not installed or correctly linked.fixEnsure `npm install react-native-automerge-generated` (and other relevant peer deps like `react-native-quick-crypto`) has been run, and follow any platform-specific linking instructions for React Native. -
TypeError: WebCrypto is not defined
cause The runtime environment (e.g., older Node.js versions, certain browser contexts, or improperly configured Expo/React Native) lacks a global `crypto.subtle` API, which is essential for MindooDB's cryptographic operations.fixFor Node.js, ensure you are on a recent version (>=15.0.0) or provide a suitable polyfill. For Expo/React Native, verify that `expo-standard-web-crypto` is installed and correctly configured as per its documentation.
Warnings
- breaking MindooDB is currently in 'Alpha software' status (v0.0.17). This means APIs are highly unstable and may change significantly without notice between minor or even patch versions. It is not recommended for production use where stability is critical.
- gotcha While MindooDB offers end-to-end encryption, its alpha status means the cryptographic implementations and overall security posture are still under development and unvetted. It should not be assumed production-ready or fully secure until it reaches a stable release and undergoes independent security audits.
- gotcha MindooDB relies on several peer dependencies, particularly for React Native environments (e.g., `react-native-automerge-generated`, `react-native-quick-crypto`, `expo-standard-web-crypto`). Failure to install these correctly can lead to runtime errors or missing functionality in specific environments.
Install
-
npm install mindoodb -
yarn add mindoodb -
pnpm add mindoodb
Imports
- MindooDB
const MindooDB = require('mindoodb');import { MindooDB } from 'mindoodb'; - MindooDB (Web)
import { MindooDB } from 'mindoodb';import { MindooDB } from 'mindoodb/browser'; - MindooDocument
import { MindooDocument } from 'mindoodb';import { type MindooDocument } from 'mindoodb';
Quickstart
import { MindooDB, type MindooDocument } from 'mindoodb';
async function initializeAndUseMindooDB() {
// IMPORTANT: For production, manage user passwords securely and do NOT hardcode.
// This password is used to derive encryption keys for the user's data.
const userPassword = process.env.MINDOODB_PASSWORD ?? 'secure-dev-password-123';
const userId = 'my-unique-user-id'; // A unique identifier for the current user
console.log('Initializing MindooDB...');
// Instantiate MindooDB. In a real application, you'd configure a persistent
// storage adapter (e.g., IndexedDB for web) and potentially a sync service.
const db = new MindooDB({
userId: userId,
password: userPassword,
});
await db.init();
console.log(`MindooDB initialized for user: ${userId}`);
// 1. Create a new end-to-end encrypted document
console.log('Creating a new document...');
const newDocument: MindooDocument = await db.createDocument({
type: 'secret-note',
title: 'Top Secret Plan',
content: 'Phase 1: Encrypt everything. Phase 2: Distribute. Phase 3: Profit.',
tags: ['secret', 'plan', 'e2e']
});
console.log(`Document created with ID: ${newDocument.id}`);
console.log('Initial document content (decrypted client-side):', newDocument.content);
// 2. Update the document
console.log('Updating the document...');
await newDocument.update(currentDoc => {
currentDoc.content = 'Phase 1: Encrypt everything. Phase 2: Securely distribute. Phase 3: Achieve peace.';
return currentDoc;
});
console.log('Document updated.');
// 3. Retrieve and verify the document
console.log('Retrieving the document...');
const retrievedDocument = await db.getDocument<MindooDocument>(newDocument.id);
if (retrievedDocument) {
console.log(`Retrieved document ID: ${retrievedDocument.id}`);
console.log('Retrieved document title:', retrievedDocument.title);
console.log('Retrieved document content (decrypted client-side):', retrievedDocument.content);
console.log('This data was never exposed in plaintext to any server.');
} else {
console.error('Failed to retrieve document.');
}
// In a real scenario, you would connect to a sync server to exchange
// encrypted changes with other clients, e.g., await db.sync();
}
initializeAndUseMindooDB().catch(console.error);