NotariumDocumentation
Documentation version: latest
EN

Environment variables

Notarium is configured through environment variables. The defaults just work — for a local run you don't need to fill in anything: copy .env.example to .env and edit the lines you actually need. The Docker stack passes .env into the container as-is (values are not baked into the image), so the same file describes both your local and your production instance.

cp .env.example .env      # the defaults work — edit only what you need

Below is the full reference. Some variables are set directly in .env.example; others (search fine-tuning) have defaults in code and aren't spelled out in the example — those are flagged separately.

Core

The basics: port, authentication mode, and the location of the metadata database and spaces.

VariablePurposeDefaultExample
DATA_DIRThe single data knob: the root from which everything else is derived — the metadata database, indexes, notes, artifacts. Unset → a sensible default is used./data (Docker); ~/.local/share/notarium (host)DATA_DIR=/srv/notarium
PORTThe port the backend listens on; a single Fastify listener serves /api, /mcp, and the SPA's static assets.3000PORT=3000
AUTH_MODEAuthentication mode: password (login plus a first-run setup screen, requires the metadata database) or none (a single all-access principal for desktop/dev/trusted intranet, no login UI).passwordAUTH_MODE=none
META_DB_URLThe metadata database: identity, revision log, space registry, authentication, projects. Defaults to sqlite under DATA_DIR, so password mode works with no setup. Optional: set it only to move metadata state into an external Postgres (shared state, HA).sqlite:<DATA_DIR>/meta.dbMETA_DB_URL=postgres://user:pass@db:5432/notarium
SPACES_ROOTThe root where each space is a folder; enables creating spaces from the UI at runtime. Optional: defaults to <DATA_DIR>/spaces, set it only if your notes live outside the data root.<DATA_DIR>/spacesSPACES_ROOT=/mnt/notes
SPACES_CONFIGExplicit space topology: inline JSON or a path to a JSON file. Overrides the single-space variables.unsetSPACES_CONFIG=/data/spaces.json
ENGINE_DATA_DIRWhere the engine keeps derived indexes — one file per space. The file name follows the space's folder name and doesn't change when the space is renamed. Deleting the directory → a reindex at startup; the index is recoverable. Optional: defaults to <DATA_DIR>/engine, set it to move the indexes onto another disk.<DATA_DIR>/engineENGINE_DATA_DIR=/mnt/ssd/engine
JOBS_DATA_DIRThe job directory: artifacts of async exports (derived, cleaned up by TTL) and the uploaded files of an unfinished import — those live exactly as long as their job does, which is why they belong in a backup. Optional: defaults to <DATA_DIR>/jobs, set it to move it onto another disk.<DATA_DIR>/jobsJOBS_DATA_DIR=/mnt/ssd/jobs
SPACE_IDLE_EVICT_SECONDSEvict the read model of an idle space. 0 — keep it warm; spaces with a live SSE connection are never evicted.0SPACE_IDLE_EVICT_SECONDS=900
SYNC_POLL_SECONDSThe polling interval for external on-disk changes (each poll is a full space rescan). 0 — disable polling. For unwatchable mounts (network volume, in-memory) the effective interval is capped at 60 s.120SYNC_POLL_SECONDS=0
PUBLIC_BASE_URLThe canonical external address of the instance behind a reverse proxy — for the OAuth metadata of MCP connectors. Without it, the address is derived from the proxy's forwarded headers.unsetPUBLIC_BASE_URL=https://notes.example.com
TRUST_PROXYA comma-separated list of IPs/CIDRs of the immediate proxies — used to derive the real client IP for login rate limits and for admitting new OAuth clients. Unset means the safe default: X-Forwarded-For has no effect on the limits. Boolean values, hop counts, named ranges, and all-address ranges (/0) are rejected at startup.unsetTRUST_PROXY=172.18.0.0/16
Metadata database vs. files

Two different things live on disk. SPACES_ROOT is the Markdown truth (your notes, one folder per space). META_DB_URL is the metadata database: what can't be derived from the files (users, access, version history). More in the Self-host section.

Single-space (bare-host, no Docker)

For running a single space without SPACES_CONFIG and without SPACES_ROOT (for example, a local bare run without Docker).

VariablePurposeDefaultExample
ENGINEThe engine for a single space. The only value is notarium; you can leave it unset.notariumENGINE=notarium
NOTES_DIRAbsolute path to the notes folder of a single space (single-space mode).unsetNOTES_DIR=/home/me/notes

Lexical full-text search (FTS) always works, with no configuration. Semantic (vector) and hybrid search are opt-in: a heavy native stack (onnxruntime + sqlite-vec, ~660 MB on disk) plus the bge-m3 embedding model (~600 MB on disk, hundreds of MB of RAM). The variables below have defaults in code and aren't spelled out in .env.example.

VariablePurposeDefaultExample
VECTOR_SEARCHon/off — turns on semantics and hybrid fusion. When the native stack is missing, on falls back to full-text search — without error.on (code), off (published image)VECTOR_SEARCH=on
EMBED_MODELThe id of the embedding model (transformers.js/ONNX). Set it together with EMBED_DIMENSIONS.Xenova/bge-m3EMBED_MODEL=Xenova/multilingual-e5-small
EMBED_DIMENSIONSThe vector width; it must match the model (bge-m3 — 1024, e5-small — 384). A mismatch is fail-closed: the note stays FTS-only.1024EMBED_DIMENSIONS=384
EMBED_DTYPEModel quantization: fp32 / fp16 / q8 / q4.q8EMBED_DTYPE=fp16
EMBED_THREADSThe number of ONNX intra-op threads per background-indexing worker (a pool of EMBED_WORKERS workers).1 per worker (no-pool fallback — half the cores)EMBED_THREADS=2
EMBED_WORKERSThe size of the embedding worker_threads pool = background-indexing parallelism across cores. Each worker holds its own copy of the model (this affects RAM).max(1, min(cores−2, 4))EMBED_WORKERS=8
EMBED_QUERY_PREFIX / EMBED_PASSAGE_PREFIXPrefixes for asymmetric models (e5). For the symmetric bge-m3, leave them unset — otherwise quality drops in ways you won't notice.unsetEMBED_QUERY_PREFIX="query: "
EMBED_CPU_MEM_ARENAon/off. off keeps consumption flat at ~1.9 GB of RAM for bge-m3 — a guard against OOM on a tight, swapless machine (with on the arena can creep up to several GB).onEMBED_CPU_MEM_ARENA=off
GRAPH_BOOSTon/off — a third RRF channel (a graph boost over links, 1-hop wikilink). Inert when VECTOR_SEARCH=off.offGRAPH_BOOST=on
Two independent switches

For semantics to work locally you need both: the native stack installed (make deps-vector; the default make deps does not install it, the published image always ships it) and VECTOR_SEARCH=on. If the stack is missing, on falls back to lexical full-text search — without error. More in the Search and Search setup sections.

Backup and restore

The built-in backup, backup verify, and restore commands work with no configuration. The variables below only matter when the container root is mounted read-only or your data is noticeably larger than typical. More in Backup and restore.

VariablePurposeDefaultExample
NOTARIUM_BACKUP_TMPDIRThe directory for the intermediate files of a backup, a verify, or a restore. Set it if the container root is read-only or /tmp is short on space: a streaming backup may temporarily need room for the archive plus two expanded stages./tmpNOTARIUM_BACKUP_TMPDIR=/mnt/scratch
NOTARIUM_BACKUP_MAX_BYTESThe size ceiling — for both the compressed input and the expanded payload. A zip-bomb guard; only large, trusted installations raise it.64 GiBNOTARIUM_BACKUP_MAX_BYTES=137438953472
NOTARIUM_BACKUP_MAX_ENTRIESThe ceiling on the number of entries in the archive.1000000NOTARIUM_BACKUP_MAX_ENTRIES=2000000
NOTARIUM_BACKUP_MAX_METADATA_BYTESA separate memory ceiling for names, the ZIP's internal structures, and manifest.json.32 MiBNOTARIUM_BACKUP_MAX_METADATA_BYTES=67108864

Docker and build

VariablePurposeDefaultExample
IMAGE / TAGThe image reference for docker compose / make up. The main install path is the public image docouno/notarium:latest; override the coordinate to use your own registry or a specific tag.docouno/notarium:latestIMAGE=docouno/notarium TAG=latest
GIT_SHA / BUILD_TIMEBuild-args; inlined into GET /api/about and the Settings → About tab. Without them — null.emptyGIT_SHA=$(git rev-parse --short HEAD)
The image and building from source

docouno/notarium:latest is the public image and the main install path; IMAGE / TAG set which image docker compose / make up will pull. If the image hasn't been pulled from the registry yet — build from source in the main repository: make up (the behavior is identical).

See also