Markdown DB Engine is a transactional content database whose formal business Records are Markdown files. Applications use typed queries, Schema, indexes and transactions; humans and Agents can edit ordinary Markdown Workspaces and explicitly Merge reviewed changes back into the Runtime Database.
It is designed for articles, knowledge bases, CMS content, Agent Memory and project archives. It is not a high-frequency event store or a distributed SQL database.
- Node.js 22 or newer
- ESM for the TypeScript/JavaScript SDK
- A local filesystem for the Runtime Database and Workspaces
Start the Local Server and open the Web UI without installing globally:
npx md-db-engine serve ./content.mddb --openOn a new Database, the terminal prints a generated first Owner Credential exactly once. Paste that owner:secret value into the Web UI sign-in form. The Server listens only on 127.0.0.1:3000 unless you explicitly configure another address.
The Database remains in ./content.mddb. Stopping or upgrading the npm package does not delete that directory.
Useful options:
npx md-db-engine serve ./content.mddb --port 4100
npx md-db-engine serve ./content.mddb --bootstrap-username owner --bootstrap-secret "$MDDB_OWNER_SECRET"
npx md-db-engine serve --helpInstall the package in an application:
npm install md-db-engineCreate, query and reopen a Database:
import { openDatabase } from 'md-db-engine'
const database = await openDatabase({ path: './content.mddb' })
const articles = database.collection('articles')
await articles.insert({
id: 'hello',
title: 'Hello',
status: 'draft',
body: '# Hello\n\nMarkdown is the formal Record body.',
})
const result = await articles.find({
where: { field: 'status', operator: 'eq', value: 'draft' },
orderBy: [{ field: 'title', direction: 'asc' }],
limit: 20,
})
console.log(result.records)
await database.close()For ordinary Document Collections, title is a required system field and becomes the safe default Markdown filename, while id remains the stable Record identity. For example, the Record above is stored as Hello.md. Titles must be unique inside a Collection after filename sanitization, Unicode normalization, and case folding; a conflict is rejected instead of receiving an opaque suffix. Table and Records layouts keep their grouped filenames.
Transactions can span Collections:
await database.transaction(async (transaction) => {
await transaction.collection('articles').patch('article-id', {
status: 'published',
})
await transaction.collection('authors').patch('author-id', {
publishedCount: 4,
})
})Only one Writer Host can open a Runtime Database at a time. When the Local Server is running, other applications must use the Remote SDK or HTTP API instead of calling openDatabase() for the same directory.
Install the command for long-running local use:
npm install --global md-db-engine
md-db-engine serve ./content.mddb --openStandard command information:
md-db-engine --help
md-db-engine --version
md-db-engine serve --helpQuery the running Server:
md-db-engine query \
--endpoint http://127.0.0.1:3000 \
--credentials 'owner:replace-with-your-secret' \
--collection articles \
--limit 20 \
--jsonEmbedded CLI operations use --database; Remote operations use --endpoint and a Credential.
Export a freely editable Workspace:
md-db-engine workspace export \
--database ./content.mddb \
--workspace ./workspace \
--jsonEdit files under ./workspace with VS Code, Obsidian, shell tools or an Agent. The Runtime Database does not watch the directory and does not receive unreviewed changes.
Review and apply changes explicitly:
md-db-engine merge plan \
--database ./content.mddb \
--workspace ./workspace \
--json
md-db-engine merge apply \
--database ./content.mddb \
--workspace ./workspace \
--yes \
--jsonA Merge Plan detects additions, changes, deletions, moves, Schema changes and concurrent conflicts. Apply rejects a stale Plan if either the Runtime or Workspace changed after planning.
Migration is a one-time scan → preview → apply workflow. The source Vault is not modified by Scan or Preview, and Apply writes only the eligible Markdown identities, generated Schema, and signed Workspace metadata.
First, inspect the Vault and write the suggested configuration to a separate review directory:
md-db-engine init scan ./my-vault \
--output ./my-vault-migration-reviewReview ./my-vault-migration-review/init-report.md and edit mddb.init.yaml. Its include/exclude rules decide the one-time import set; they do not become permanent database configuration.
Preview the exact eligible and pending files without changing the Vault:
md-db-engine init preview ./my-vault \
--config ./my-vault-migration-review/mddb.init.yaml \
--plan ./my-vault-migration-review/migration-plan.jsonAfter reviewing the generated Plan, apply it to a new Runtime Database path:
md-db-engine init apply ./my-vault \
--plan ./my-vault-migration-review/migration-plan.json \
--database ./databases/my-vault.mddb \
--yesApply creates an external byte-for-byte backup before changing the Vault, adds UUIDv7 id, collection, and a filename-derived title when missing, preserves existing Frontmatter and Body text, creates the Runtime Database, and establishes signed .mddb/ metadata. Ambiguous or invalid files remain unchanged in the pending list while the eligible set commits atomically.
After migration, Manifest entries define the managed Record set. Unmanaged templates, drawings, reports, and ordinary Markdown remain in the Vault without blocking Workspace operations. A new file joins normal Merge discovery when it declares a valid collection; Merge generates a missing UUIDv7 id and filename-derived title, then writes them back only after Apply succeeds. The one-time migration config is no longer consulted.
If the Local Server is running, submit Obsidian changes through the Server instead of opening the same Database again:
md-db-engine merge plan \
--endpoint http://127.0.0.1:3000 \
--credentials 'owner:replace-with-your-secret' \
--workspace ./my-vault \
--json
md-db-engine merge apply \
--endpoint http://127.0.0.1:3000 \
--credentials 'owner:replace-with-your-secret' \
--workspace ./my-vault \
--yes \
--jsonImages, PDFs and other binary assets remain in the Vault or external asset storage; the Runtime Database manages the selected Markdown Records and does not copy those binaries.
The npm package includes two installable Skills under skills/dist/:
mddb-vault-migration.skillanalyzes an existing Vault, prepares semantic Collection rules and Preview, pauses for explicit Apply approval, then verifies Backup, Runtime and Workspace behavior.mddb-app-builder.skillinspects the real Schema, chooses Embedded or Remote SDK, creates an application boundary and verifies Query, Mutation, tests and production build.
Extract the target .skill package with the Skill installer supported by your Coding Agent, or copy the corresponding source directory from node_modules/md-db-engine/skills/ into that Agent's local Skills directory. Installation paths differ by Agent product; the bundled SKILL.md remains the portable entry point.
md-db-engine check --database ./content.mddb --json
md-db-engine backup --database ./content.mddb --json
md-db-engine upgrade --database ./content.mddb --yes --json
md-db-engine index rebuild --database ./content.mddb --yes --jsonRestore always writes to a new directory:
md-db-engine restore \
--database ./content.mddb \
--snapshot <snapshot-id> \
--target ./recovered.mddb \
--yes \
--jsonThe serve command accepts flags or the corresponding environment variables:
| CLI option | Environment variable | Purpose |
|---|---|---|
<database> |
MDDB_DATABASE |
Default Runtime Database directory |
--database-root |
MDDB_DATABASE_ROOT |
Managed Database root |
--host |
MDDB_HOST |
Listen address |
--port |
MDDB_PORT |
Listen port |
--bootstrap-username |
MDDB_BOOTSTRAP_USERNAME |
First Owner username |
--bootstrap-secret |
MDDB_BOOTSTRAP_SECRET |
First Owner secret |
--allowed-origins |
MDDB_ALLOWED_ORIGINS |
Browser origins |
--tls-key |
MDDB_TLS_KEY |
TLS private key path |
--tls-certificate |
MDDB_TLS_CERTIFICATE |
TLS certificate path |
--authentication |
MDDB_AUTHENTICATION=true |
External listener authentication gate |
--access-log |
MDDB_ACCESS_LOG=true |
JSON access log |
An external listener is rejected unless TLS, Authentication, Allowed Origins and Access Log are all configured. Keep the default Loopback address for ordinary local use.
Secrets must not enter source control, Workspace files or access logs. Prefer environment variables or a Secret Manager rather than command flags for persistent credentials.
- Package root: Embedded and Remote TypeScript SDK
md-db-engine/server: programmatic Local Server APImd-db-engine/cli: programmatic non-interactive CLI adapter/v1/openapi.json: OpenAPI 3.1 HTTP contract/v1/events: committed transaction events over SSEmd-db-engine: installable command
Apache-2.0. See LICENSE.