CLI

The CLI tool trilium-alchemy manages Trilium by building on core SDK functionality.

Configuration

The tool can be configured via any of the following, in order of precedence:

  • .yaml file

    • Supports multiple Trilium instances

  • Command-line options

  • Environment variables

  • .env file

Config file example

# optional top-level data dir with subfolders per instance
root_data_dir:
  "./trilium_data"

# mapping of instance names to info
instances:
  my-notes:
    # connection info, either "token" or "password" required
    host: "http://localhost:8080"
    token: "MY_TOKEN"
    password: "MY_PASSWORD"

    # optional data dir which overrides root_data_dir/[instance]
    data_dir: "./my-notes-data"

    # optional fully-qualified class name of root note for tree push
    root_note_fqcn: "my_notes.root.RootNote"

Filesystem note format

The CLI represents Trilium notes on the filesystem using a prefix tree structure designed for efficient storage and retrieval of large note collections. As Trilium is intended to scale to 100,000+ notes, this format is designed to scale accordingly.

For more background on Trilium’s scaling capability, see the documentation on Scalability:

My rule of thumb for estimation of size of personal knowledge base is that you can reasonably produce around 10 notes a day, which is 3650 in a year. I plan to use my knowledge base long term (with or without Trilium Notes), probably decades so you can easily get to number 100 000 or even more. Right now, my personal knowledge base has around 10 000 notes.

100 000 is a number to which most note taking software doesn’t scale well (in both performance and UI). Yet I don’t think it’s really very much considering a lifetime of knowledge.

Design goals

This format is designed with the following goals in mind:

  • Source control friendliness: Note metadata should be stored as text while preserving the exact information captured in Trilium

  • Diff minimization: A single change in the UI (e.g. reordering a child note or adding an attribute) should ideally result in a single line changed in the filesystem representation

  • Human readability: While the filesystem format is not necessarily intended to be edited by hand, it should be accessible upon inspection and feasible to modify, either manually or via external software

Directory structure

Notes are organized in a hierarchical prefix tree with 2 levels of depth:

/dump_root/
├── a1/
│   ├── b2/
│   │   ├── c3d4e5f6g7h8i9j0k1l2m3n4o5p6/
│   │   │   ├── meta.yaml
│   │   │   └── content.txt
│   │   └── x9y8z7w6v5u4t3s2r1q0p9o8n7m6/
│   │       ├── meta.yaml
│   │       └── content.bin
│   └── b3/
│       └── ...
└── a2/
    └── ...

Each note is stored in a folder named using a hash of its note ID:

  • Prefix levels: 2 levels of 2-character hex prefixes (e.g., a1/b2/)

  • Note folder: 28-character hex suffix containing the note’s files

Rationale for prefix tree

The prefix tree structure provides several benefits:

  • Case-insensitive filesystem compatibility: Hex values ensure there cannot be collisions on case-insensitive systems (note IDs use both upper- and lowercase letters)

  • Efficient directory traversal: Limits files per directory to 256, avoiding filesystem performance issues

  • Deterministic mapping: Same note ID always maps to the same filesystem location

Note representation

Each note folder contains exactly two files:

Note metadata: meta.yaml

Contains structured metadata about the note:

id: "X6WplkgKJr5C"
type: "text"
mime: "text/html"
title: "My Note"
blob_id: "7XJSwh6apxkriWy2bX9P"
attributes:
  - "label1=value1"
  - "label2(inheritable)=value2"
  - "~relation1=5t6q5vF3hIx0"
children:
  - "yR0GpxGrUu6e|My prefix"
  - "ZCLwYMwtqjTu|"

Attribute and child branch IDs and positions are not explicitly stored. This approach is aligned with the “diff friendly” design goal.

Content file

  • Text notes: content.txt (UTF-8 encoded)

  • Binary notes: content.bin (raw bytes)

The content file type is determined by the note’s type and mime type.

Filesystem operations

The filesystem format supports bidirectional synchronization:

Dump (Trilium → Filesystem)

  • Creates/updates note folders based on current Trilium state

  • Compares content hashes to avoid unnecessary file writes

  • Prunes stale folders from deleted notes

Load (Filesystem → Trilium)

  • Recreates notes from filesystem representation

  • Preserves all metadata (note fields, attributes, branches) and content

  • Can target specific parent notes for orphaned subtrees

    • Otherwise, syncs notes “in-place” assuming they are already placed in the hierarchy

Scan

  • Updates metadata when content files are modified externally

    • Otherwise content changes would not be propagated back to Trilium as content comparison is done based on hashes rather than raw data

  • Useful after manual filesystem edits

Example use cases

The following illustrates some common use cases, not covering all available options and functionality.

Multi-instance configuration

Work with multiple Trilium instances using config files:

# check connection using specific instance from config
trilium-alchemy --instance my-private-notes --config-file my-config.yaml check
trilium-alchemy --instance my-public-notes --config-file my-config.yaml check

Filesystem dump/load

Synchronize notes with filesystem representation as described above:

# dump entire note tree to filesystem
trilium-alchemy fs dump /path/to/fs-tree

# load filesystem dump back to Trilium
trilium-alchemy fs load /path/to/fs-tree

# dump subtree to filesystem
trilium-alchemy fs dump --search "#myCoolProject" /path/to/my-cool-project

# load subtree from filesystem and place as child of specific parent note
trilium-alchemy fs load --parent-search "#myProjects" /path/to/my-cool-project

# scan filesystem for content changes and update metadata
trilium-alchemy fs scan /path/to/fs-tree

Database backup/restore

Create database backups and restore from them:

# create backup-now.db
trilium-alchemy db backup

# create backup with auto-generated name from timestamp
trilium-alchemy db backup --auto-name

# create backup with specific name
trilium-alchemy db backup --name my-backup

# create backup and copy to specific location (requires TRILIUM_DATA_DIR or --data-dir)
trilium-alchemy db backup --dest /path/to/backup-now.db

# verify backup timestamp after creation (requires TRILIUM_DATA_DIR or --data-dir)
trilium-alchemy db backup --verify

# restore from backup (requires TRILIUM_DATA_DIR or --data-dir)
trilium-alchemy db restore /path/to/backup.db

.zip export/import

Export and import note trees as .zip archives:

# export entire note tree
trilium-alchemy tree export /path/to/my-notes.zip

# export specific subtree by search
trilium-alchemy tree --search "#myCoolProject" export /path/to/my-cool-project.zip

# import notes to root
trilium-alchemy tree import /path/to/my-notes.zip

# import subtree as child of specific note by search
trilium-alchemy tree --search "#myProjects" import /path/to/my-cool-project.zip

Template sync

As you develop templates, you may want to keep existing instances up to date. Attributes are inherited, but child notes are not updated when you update the template.

This command enables you to perform such re-synchronization of template instances with their templates:

# sync all template instances with their templates
trilium-alchemy note sync-template

# sync instances of specific template only
trilium-alchemy note sync-template --template-search "#template #task"

Template sync performs the following recursively:

  • Adds new child notes from template to instances

  • Reorders child notes matched by title

  • Recreates any cloning structure in the template

  • Preserves instance-specific modifications (places extra child notes at end)

This feature works with both regular templates (#template) and workspace templates (#workspaceTemplate).

Usage

trilium-alchemy

trilium-alchemy Usage: trilium-alchemy [OPTIONS] COMMAND [ARGS]... TriliumAlchemy CLI Toolkit                                                     ╭─ Options ────────────────────────────────────────────────────────────────────╮ *--hostTEXTTrilium host, e.g. http://localhost:8080       [env var: TRILIUM_HOST]                        [default: None]                                [required]                                     --tokenTEXTETAPI token                                    [env var: TRILIUM_TOKEN]                       [default: None]                                --passwordTEXTTrilium password                               [env var: TRILIUM_PASSWORD]                    [default: None]                                --instanceTEXTInstance name as configured in .yaml           [env var: TRILIUM_INSTANCE]                    [default: None]                                --config-fileFILE.yaml file containing instance info, only      applicable with --instance                     [env var: TRILIUM_ALCHEMY_CONFIG_FILE]         [default: trilium-alchemy.yaml]                --helpShow this message and exit.                    ╰──────────────────────────────────────────────────────────────────────────────╯ ╭─ Commands ───────────────────────────────────────────────────────────────────╮ check Check Trilium connection                                             fs    Filesystem operations using TriliumAlchemy's note format             db    Database maintenance operations                                      tree  Operations on tree or subtree                                        note  Operations on one or more notes, not necessarily in the same subtree ╰──────────────────────────────────────────────────────────────────────────────╯

check

check Usage: trilium-alchemy check [OPTIONS] Check Trilium connection                                                       ╭─ Options ────────────────────────────────────────────────────────────────────╮ --helpShow this message and exit.                                  ╰──────────────────────────────────────────────────────────────────────────────╯

fs

fs Usage: trilium-alchemy fs [OPTIONS] COMMAND [ARGS]... Filesystem operations using TriliumAlchemy's note format                       ╭─ Options ────────────────────────────────────────────────────────────────────╮ --helpShow this message and exit.                                  ╰──────────────────────────────────────────────────────────────────────────────╯ ╭─ Commands ───────────────────────────────────────────────────────────────────╮ dump Dump notes to folder                                                  load Load notes from dump folder and optionally add as children of given   parent                                                                scan Scan dump folder for content file changes and update metadata if out  of date                                                               ╰──────────────────────────────────────────────────────────────────────────────╯
dump
dump Usage: trilium-alchemy fs dump [OPTIONS] DEST Dump notes to folder                                                           ╭─ Arguments ──────────────────────────────────────────────────────────────────╮ *destDIRECTORYDestination folder                                 [default: None]                                    [required]                                         ╰──────────────────────────────────────────────────────────────────────────────╯ ╭─ Options ────────────────────────────────────────────────────────────────────╮ --note-idTEXTNote id to dump                            [default: root]                            --searchTEXTSearch string to identify note(s) to dump, e.g. '#myProjectRoot'                      [default: None]                            --no-recurseDon't recursively dump child notes         --no-pruneDon't propagate deleted notes in           destination folder                         --check-content-hashCheck hash of content file instead of      using dump metadata when determining       whether content is out of date             --dry-runDon't update filesystem, only log          operations                                 --helpShow this message and exit.                ╰──────────────────────────────────────────────────────────────────────────────╯
load
load Usage: trilium-alchemy fs load [OPTIONS] SRC Load notes from dump folder and optionally add as children of given parent     ╭─ Arguments ──────────────────────────────────────────────────────────────────╮ *srcDIRECTORYSource folder                                       [default: None]                                     [required]                                          ╰──────────────────────────────────────────────────────────────────────────────╯ ╭─ Options ────────────────────────────────────────────────────────────────────╮ --parent-note-idTEXTOptional note id of parent under which to    place loaded notes                           [default: None]                              --parent-searchTEXTOptional search string to identify parent    under which to place loaded notes, e.g.      '#myExtensionsRoot'                          [default: None]                              --dry-runOnly log pending changes                     --yes-yDon't ask for confirmation before committing changes                                      --helpShow this message and exit.                  ╰──────────────────────────────────────────────────────────────────────────────╯
scan
scan Usage: trilium-alchemy fs scan [OPTIONS] DUMP_DIR Scan dump folder for content file changes and update metadata if out of date   ╭─ Arguments ──────────────────────────────────────────────────────────────────╮ *dump_dirDIRECTORYDump folder as previously passed to dump       command                                        [default: None]                                [required]                                     ╰──────────────────────────────────────────────────────────────────────────────╯ ╭─ Options ────────────────────────────────────────────────────────────────────╮ --dry-runDon't update filesystem, only log operations              --helpShow this message and exit.                               ╰──────────────────────────────────────────────────────────────────────────────╯

db

db Usage: trilium-alchemy db [OPTIONS] COMMAND [ARGS]... Database maintenance operations                                                ╭─ Options ────────────────────────────────────────────────────────────────────╮ --data-dirDIRECTORYDirectory containing Trilium database, if not   specified in config file                        [env var: TRILIUM_DATA_DIR]                     [default: None]                                 --helpShow this message and exit.                     ╰──────────────────────────────────────────────────────────────────────────────╯ ╭─ Commands ───────────────────────────────────────────────────────────────────╮ backup  Backup database, optionally copying to destination path            restore Restore database from file                                         ╰──────────────────────────────────────────────────────────────────────────────╯
backup
backup Usage: trilium-alchemy db backup [OPTIONS] Backup database, optionally copying to destination path                        ╭─ Options ────────────────────────────────────────────────────────────────────╮ --nameTEXTName of backup in Trilium data dir to generate,     e.g. 'now' will write 'backup-now.db'               [default: now]                                      --auto-nameWhether to use current datetime as name instead of  --name option                                       --verifyWhether to verify by ensuring backup's mtime is <   10 seconds ago (requires db --data-dir)             --destPATHOptional destination database file or folder to     copy backup; if folder, filename will use current   datetime (requires db --data-dir)                   [default: None]                                     --overwriteWhether to overwrite destination file if it already exists                                              --helpShow this message and exit.                         ╰──────────────────────────────────────────────────────────────────────────────╯
restore
restore Usage: trilium-alchemy db restore [OPTIONS] SRC Restore database from file                                                     ╭─ Arguments ──────────────────────────────────────────────────────────────────╮ *srcFILESource database file                                     [default: None]                                          [required]                                               ╰──────────────────────────────────────────────────────────────────────────────╯ ╭─ Options ────────────────────────────────────────────────────────────────────╮ --dry-runDon't copy, only log source/destination paths           --yes-yDon't ask for confirmation before overwriting           document.db                                             --helpShow this message and exit.                             ╰──────────────────────────────────────────────────────────────────────────────╯

tree

tree Usage: trilium-alchemy tree [OPTIONS] COMMAND [ARGS]... Operations on tree or subtree                                                  ╭─ Options ────────────────────────────────────────────────────────────────────╮ --note-idTEXTNote id on which to perform operation                 [default: root]                                       --searchTEXTSearch string to identify note on which to perform    operation, e.g. '#myProjectRoot'                      [default: None]                                       --helpShow this message and exit.                           ╰──────────────────────────────────────────────────────────────────────────────╯ ╭─ Commands ───────────────────────────────────────────────────────────────────╮ export            Export subtree to .zip file                              import            Import subtree from .zip file                            push              Push declarative note subtree to target note             cleanup-positions Set attribute and branch positions to intervals of 10,   starting with 10                                         ╰──────────────────────────────────────────────────────────────────────────────╯
export
export Usage: trilium-alchemy tree export [OPTIONS] DEST Export subtree to .zip file                                                    ╭─ Arguments ──────────────────────────────────────────────────────────────────╮ *destFILEDestination .zip file                                   [default: None]                                         [required]                                              ╰──────────────────────────────────────────────────────────────────────────────╯ ╭─ Options ────────────────────────────────────────────────────────────────────╮ --format[html|markdown]Export format                            [default: html]                          --overwriteWhether to overwrite destination file if it already exists                        --helpShow this message and exit.              ╰──────────────────────────────────────────────────────────────────────────────╯
import
import Usage: trilium-alchemy tree import [OPTIONS] SRC Import subtree from .zip file                                                  ╭─ Arguments ──────────────────────────────────────────────────────────────────╮ *srcFILESource .zip file                                         [default: None]                                          [required]                                               ╰──────────────────────────────────────────────────────────────────────────────╯ ╭─ Options ────────────────────────────────────────────────────────────────────╮ --helpShow this message and exit.                                  ╰──────────────────────────────────────────────────────────────────────────────╯
push
push Usage: trilium-alchemy tree push [OPTIONS] [NOTE_FQCN] Push declarative note subtree to target note                                   ╭─ Arguments ──────────────────────────────────────────────────────────────────╮ note_fqcn[NOTE_FQCN]Fully-qualified class name of                  BaseDeclarativeNote subclass                   [default: None]                                ╰──────────────────────────────────────────────────────────────────────────────╯ ╭─ Options ────────────────────────────────────────────────────────────────────╮ --dry-runOnly show pending changes                               --yes-yDon't ask for confirmation before committing changes    --helpShow this message and exit.                             ╰──────────────────────────────────────────────────────────────────────────────╯
cleanup-positions
cleanup-positions Usage: trilium-alchemy tree cleanup-positions [OPTIONS] Set attribute and branch positions to intervals of 10, starting with 10        ╭─ Options ────────────────────────────────────────────────────────────────────╮ --dry-runOnly log pending changes                                --yes-yDon't ask for confirmation before committing changes    --helpShow this message and exit.                             ╰──────────────────────────────────────────────────────────────────────────────╯

note

note Usage: trilium-alchemy note [OPTIONS] COMMAND [ARGS]... Operations on one or more notes, not necessarily in the same subtree           ╭─ Options ────────────────────────────────────────────────────────────────────╮ --note-idTEXTNote id on which to perform operation                 [default: None]                                       --searchTEXTSearch string to identify note(s) on which to perform operation, e.g. '#myProjectRoot'                      [default: None]                                       --helpShow this message and exit.                           ╰──────────────────────────────────────────────────────────────────────────────╯ ╭─ Commands ───────────────────────────────────────────────────────────────────╮ sync-template Sync notes with specified template, or first ~template       relation if no template provided; select all applicable      notes if none passed                                         ╰──────────────────────────────────────────────────────────────────────────────╯
sync-template
sync-template Usage: trilium-alchemy note sync-template [OPTIONS] Sync notes with specified template, or first ~template relation if no template provided; select all applicable notes if none passed                           ╭─ Options ────────────────────────────────────────────────────────────────────╮ --template-note-idTEXTTemplate note id                           [default: None]                            --template-searchTEXTSearch string to identify template note,   e.g. '#template #task'                     [default: None]                            --dry-runOnly log pending changes                   --yes-yDon't ask for confirmation before          committing changes                         --helpShow this message and exit.                ╰──────────────────────────────────────────────────────────────────────────────╯