14 KiB
Logseq CLI (Node)
The Logseq CLI is a Node.js program compiled from ClojureScript that connects to a db-worker-node server managed by the CLI. When installed, the CLI binary name is logseq.
Build the CLI
clojure -M:cljs compile logseq-cli db-worker-node
yarn db-worker-node:release:bundle
yarn db-worker-node:release:bundle compiles and bundles db-worker-node with @vercel/ncc, and writes a standalone runtime to dist/db-worker-node.js plus an asset manifest at dist/db-worker-node-assets.json (which may contain an empty assets array when no extra files are required).
db-worker-node lifecycle
logseq manages db-worker-node automatically. You should not start the server manually. The server binds to localhost on a random port and records that port in the repo lock file.
Desktop + CLI shared semantics:
- Electron desktop and CLI are expected to use the same
db-worker-nodeand lock-file protocol for a graph. - Disk SQLite under
~/logseq/graphsis the source of truth; OPFS periodic export is not part of the desktop primary write path. - If a daemon already exists for the graph, CLI reuses it via lock-file discovery instead of starting a second writer.
- If lock ownership is invalid or stale, startup cleans stale lock state before retrying.
- Lock metadata includes an
owner-sourcevalue (cli,electron,unknown) and lifecycle actions enforce owner boundaries. server stopandserver restartare owner-aware: CLI can only stop/restart servers it owns (or legacyunknownownership).- If lock is missing but a matching orphan
db-worker-nodeprocess still exists for the same repo/data-dir, startup performs orphan cleanup before retrying.
Run the CLI
node ./dist/logseq.js graph list
You can also use npm link to make ./dist/logseq.js globally available, run:
npm link
If installed(or linked) globally, run:
logseq graph list
Configuration
Optional configuration file: ~/logseq/cli.edn
Default data dir: ~/logseq/graphs.
Graph directories on disk are stored as user-facing graph names (for example, demo/), not logseq_db_ prefixed repo identifiers.
Migration note: If you previously used ~/.logseq/cli-graphs or ~/.logseq/cli.edn, pass --data-dir or --config to continue using those locations.
Supported keys include:
:graph:data-dir:timeout-ms:output-format(use:jsonor:ednfor scripting)
CLI flags take precedence over environment variables, which take precedence over the config file.
Verbose logging:
--verboseenables structured debug logs to stderr for CLI option parsing and db-worker-node API calls.- stdout remains reserved for command output; large payloads are truncated in debug previews.
Commands
Graph commands:
graph list- list all db graphsgraph create --graph <name>- create a new db graph and switch to itgraph switch --graph <name>- switch current graphgraph remove --graph <name>- remove a graphgraph validate --graph <name>- validate graph datagraph info [--graph <name>]- show graph metadata (defaults to current graph)graph export --type edn|sqlite --file <path> [--graph <name>]- export a graph to EDN or SQLitegraph import --type edn|sqlite --input <path> --graph <name>- import a graph from EDN or SQLite (new graph only)
For any command that requires --graph, if the target graph does not exist, the CLI returns graph not exists (except for graph create). graph import fails if the target graph already exists.
Server commands:
server list- list running db-worker-node serversserver status --graph <name>- show server status for a graphserver start --graph <name>- start db-worker-node for a graphserver stop --graph <name>- stop db-worker-node for a graphserver restart --graph <name>- restart db-worker-node for a graphdoctor [--dev-script]- run runtime diagnostics fordb-worker-node.js,data-dirpermissions, and running server readiness (--dev-scriptchecksstatic/db-worker-node.jsexplicitly)
Server ownership behavior:
server stopandserver restartcan returnserver-owned-by-otherif the daemon was started by another owner source.server startcan returnserver-start-timeout-orphanwhen lock creation times out and orphan matching processes are detected.server listhuman output includes anOWNERcolumn, andserver status/server listinclude owner metadata in structured output (--output json|edn).
Sync commands:
sync status --graph <name>- show db-sync runtime state for a graph daemonsync start --graph <name>- start db-sync websocket client for a graphsync stop --graph <name>- stop db-sync client on a graph daemonsync upload --graph <name>- upload local graph snapshot to remotesync download --graph <name>- download remote graph<name>into a same-name local graph directorysync remote-graphs [--graph <name>]- list remote graphs visible to the current auth contextsync ensure-keys [--graph <name>]- ensure user RSA keys for sync/e2eesync grant-access --graph <name> --graph-id <uuid> --email <email>- grant encrypted graph access to a usersync config set [--graph <name>] ws-url|http-base|auth-token|e2ee-password <value>- set db-sync runtime config keysync config get [--graph <name>] ws-url|http-base|auth-token|e2ee-password- get db-sync runtime config keysync config unset [--graph <name>] ws-url|http-base|auth-token|e2ee-password- remove db-sync runtime config key
Sync download behavior:
sync downloadrequires--graph <name>.- If a local graph with the same name already exists, the CLI returns
graph-exists. - If no remote graph with that name exists, the CLI returns
remote-graph-not-found. sync downloadstartsdb-worker-nodein create-empty mode so local startup does not writedb-initial-databefore snapshot import.- If the target graph DB is not empty at download time, the CLI returns
graph-db-not-emptyand aborts before import. - For e2ee remote graphs in headless CLI mode, set
e2ee-passwordviasync config set(or in--config) before download.
Sync config persistence:
sync config set/unsetwrites to the CLI config file selected by--config.- If
--configis not provided, the default config path is~/logseq/cli.edn. sync config getreads from that same config source.
Inspect and edit commands:
list page [--expand] [--limit <n>] [--offset <n>] [--sort <field>] [--order asc|desc]- list pageslist tag [--expand] [--limit <n>] [--offset <n>] [--sort <field>] [--order asc|desc]- list tagslist property [--expand] [--limit <n>] [--offset <n>] [--sort <field>] [--order asc|desc]- list properties (TYPEis included by default even without--expand)upsert block --content <text> [--target-page <name>|--target-id <id>|--target-uuid <uuid>] [--pos first-child|last-child|sibling]- create blocks; defaults to today’s journal page if no target is givenupsert block --blocks <edn> [--target-page <name>|--target-id <id>|--target-uuid <uuid>] [--pos first-child|last-child|sibling]- insert blocks via EDN vectorupsert block --blocks-file <path> [--target-page <name>|--target-id <id>|--target-uuid <uuid>] [--pos first-child|last-child|sibling]- insert blocks from an EDN fileupsert block --id <id>|--uuid <uuid> [--target-id <id>|--target-uuid <uuid>|--target-page <name>] [--pos first-child|last-child|sibling] [--update-tags <edn-vector>] [--update-properties <edn-map>] [--remove-tags <edn-vector>] [--remove-properties <edn-vector>]- update and/or move a blockupsert page --page <name> [--update-tags <edn-vector>] [--update-properties <edn-map>] [--remove-tags <edn-vector>] [--remove-properties <edn-vector>]- create (or update by page name) a pageupsert page --id <id> [--update-tags <edn-vector>] [--update-properties <edn-map>] [--remove-tags <edn-vector>] [--remove-properties <edn-vector>]- update a page by id (cannot be combined with--page)upsert tag --name <name>- create or upsert a tag by nameupsert tag --id <id> [--name <name>]- validate a tag by id; when--nameis provided, rename that tag id (no-op if normalized name is unchanged)upsert tag --id <id> --name <name>conflicts: returnstag-name-conflictwhen target name is a non-tag page, andtag-rename-conflictwhen target name is another existing tagupsert property --name <name> [--type <type>] [--cardinality one|many] [--hide true|false] [--public true|false]- create or update a property by nameupsert property --id <id> [--type <type>] [--cardinality one|many] [--hide true|false] [--public true|false]- update a property by idmove --id <id>|--uuid <uuid> --target-id <id>|--target-uuid <uuid>|--target-page <name> [--pos first-child|last-child|sibling]- move a block and its children (defaults to first-child)remove --id <id>|--uuid <uuid>|--page <name>- remove blocks (by db/id or UUID) or pagessearch <query> [--type page|block|tag|property|all] [--tag <name>] [--case-sensitive] [--sort updated-at|created-at] [--order asc|desc]- search across pages, blocks, tags, and properties (query is positional)query --query <edn> [--inputs <edn-vector>]- run a Datascript query against the graphquery --name <query-name> [--inputs <edn-vector>]- run a named query (built-in or fromcli.edn)query list- list available named queriesshow --page <name> [--level <n>]- show page treeshow --uuid <uuid> [--level <n>]- show block treeshow --id <id> [--level <n>]- show block tree by db/id
Help output:
Subcommands:
list page [options] List pages
list tag [options] List tags
list property [options] List properties
upsert block [options] Upsert block
upsert page [options] Upsert page
upsert tag [options] Upsert tag
upsert property [options] Upsert property
move [options] Move block
remove [options] Remove block or page
search <query> [options] Search graph
show [options] Show tree
Options grouping:
- Help output separates Global options (apply to all commands) and Command options (command-specific flags).
Version output:
logseq --versionprints:
Build time: <timestamp>
Revision: <commit>
Output formats:
- Global
--output <human|json|edn>applies to all commands - Output formatting is controlled via global
--output,:output-formatin config, orLOGSEQ_CLI_OUTPUT. - Human output is plain text. List/search commands render tables with a final
Count: Nline. For list and search subcommands, the ID column uses:db/id(not UUID). If:db/identexists, anIDENTcolumn is included.list propertyincludes a dedicatedTYPEcolumn. Search table columns areIDandTITLE. Block titles can include multiple lines; multi-line rows align additional lines under theTITLEcolumn. Times such as listUPDATED-AT/CREATED-ATandgraph infoCreated atare shown in human-friendly relative form. Errors include error codes and may include aHint:line. Use--output json|ednfor structured output. - For
list property,TYPEis returned in default output (without--expand) for human and structured (json/edn) formats. upsert pageandupsert blockreturn entity ids indata.resultfor JSON/EDN output, and include ids in human output.- Human example:
Upserted page: [123] - Human example:
Upserted blocks: [201 202] - JSON example:
{"status":"ok","data":{"result":[123]}} - EDN example:
{:status :ok, :data {:result [123]}}
- Human example:
doctoroutput includes overall status (ok,warning,error) and per-check rows fordb-worker-script,data-dir, andrunning-servers. For scripting,--output json|ednkeeps the structured check payload.- Common doctor failures:
doctor-script-missing:db-worker-node.jsruntime target is missing (default target:dist/db-worker-node.js; usedoctor --dev-scriptto checkstatic/db-worker-node.js).doctor-script-unreadable: script path exists but is not a readable file.data-dir-permission: configured data dir is not readable or writable.doctor-server-not-ready: one or more lock-discovered servers are still in:startingstate (warning).- If bundled runtime startup fails with missing-module or missing-file errors, rebuild with
yarn db-worker-node:release:bundleand confirmdist/db-worker-node.jsexists and every path listed indist/db-worker-node-assets.jsonis present next to it.
queryhuman output returns a plain string (the query result rendered viapr-str), which is convenient for pipelines likelogseq query ... | xargs logseq show --id.- Built-in named queries currently include
block-search,task-search,recent-updated,list-status, andlist-priority. Usequery listto see the full set for your config. - Show and search outputs resolve block reference UUIDs inside text, replacing
[[<uuid>]]with the referenced block content. Nested references are resolved recursively up to 10 levels to avoid excessive expansion. For example:[[<uuid1>]]→[[some text [[<uuid2>]]]]and then<uuid2>is also replaced. showhuman output prints the:db/idas the first column followed by a tree:
id1 block1
id2 ├── b2
id3 │ └── b3
id4 ├── b4
id5 │ ├── b5
id6 │ │ └── b6
id7 │ └── b7
id8 └── b8
Examples:
node ./dist/logseq.js graph create --graph demo
node ./dist/logseq.js graph export --type edn --file /tmp/demo.edn --graph demo
node ./dist/logseq.js graph import --type edn --input /tmp/demo.edn --graph demo-import
node ./dist/logseq.js upsert block --target-page TestPage --content "hello world"
node ./dist/logseq.js move --uuid <uuid> --target-page TargetPage
node ./dist/logseq.js search "hello"
node ./dist/logseq.js show --page TestPage --output json
node ./dist/logseq.js server list
node ./dist/logseq.js doctor
node ./dist/logseq.js doctor --dev-script
node ./dist/logseq.js doctor --output json