Database

An optional, opt-in SQLite-backed store behind the SQL query and full-text search plugins.

A database is needed to run the sqlQuery and sqliteFullTextSearch plugins. It's where they build their index and the store they query against.

SQLite Node

Comark ships sqlite(), built on Node's node:sqlite. Create one and pass it to the query and search plugins:

content.ts
import { comarkContent } from 'comark-content'
import fs from 'comark-content/sources/fs'
import sqlite from 'comark-content/database/sqlite-node'
import sqlQuery from 'comark-content/plugins/sql-query'
import sqliteFullTextSearch from 'comark-content/plugins/sqlite-full-text-search'

const database = sqlite()   // one database, shared by both plugins

comarkContent({
  source: fs('./content'),
  plugins: [sqlQuery({ database }), sqliteFullTextSearch({ database })],
})

They add content.query() for SQL queries over frontmatter and content.search() for BM25 full-text search.

node:sqlite ships with Node 22.5+. To run the plugins in the browser, use sqliteWasm() instead: same API, same plugins. Being WebAssembly, it also runs in any other host without node:sqlite.

Options

sqlite(options?: SqliteOptions)
OptionTypeDefaultDescription
filenamestring':memory:'Path to the SQLite file. Omit for an in-memory database.

Persist the database

sqlite() is in-memory by default: it builds its index in RAM and drops it when the process exits, so every start rebuilds it. That's fine in development, but a serverless cold start or a fresh deploy pays the indexing cost each time.

Give it a filename and the database lives on disk instead, so a fresh instance can reuse the index rather than rebuild it:

persist.ts
import sqlite from 'comark-content/database/sqlite-node'

// In-memory (default): the index is rebuilt on every start.
sqlite()

// On disk: written once, then restored by the next instance.
sqlite({ filename: '.comark/content.db' })

To also avoid re-parsing content across restarts, cache parsed bodies with a persistent cache driver, or ship a static snapshot.

SQLite WASM

sqliteWasm() is a drop-in replacement for sqlite() that runs in any environment supporting WebAssembly: the browser, Cloudflare Workers, Vercel Edge, or Node when you don't have node:sqlite. Same interface, same filename option, same plugins:

wasm.ts
import sqliteWasm from 'comark-content/database/sqlite-wasm'
import sqlQuery from 'comark-content/plugins/sql-query'

const database = sqliteWasm()

It needs one extra dependency:

pnpm add @sqlite.org/sqlite-wasm
Exclude @sqlite.org/sqlite-wasm from Vite's dependency optimiser: the package ships a worker plus .wasm asset the optimiser doesn't handle. The official Vite plugin (comark-content/vite) does this for you.
vite.config.ts
export default defineConfig({
  optimizeDeps: {
    exclude: ['@sqlite.org/sqlite-wasm'],
  },
})
Running the whole Content instance in the browser? Hydrate sqliteWasm() from server-built snapshots instead of parsing on the client. See Artifacts & hydration.

Cache vs database

The cache and the database persist two different things. A persistent cache (or shipped artifacts) keeps parsed bodies and the manifest index, so get(), list(), and navigation() skip re-reading the source. A persistent database keeps the query and search index, so the plugins can reuse it instead of rebuilding from scratch. Persist both and a cold start does far less work.