Configuration reference¶
This page documents the supported config.toml keys for noteui.
Config file lookup and validation¶
noteui loads configuration in this order:
- If
NOTEUI_CONFIGis set, use that file path. - Otherwise use
noteui/config.tomlinside the user config directory.
If the file does not exist, noteui uses defaults.
If the file contains unknown keys or invalid values, noteui warns at startup instead of regenerating the file. It keeps the decoded portion of the config where possible and continues to use code defaults for anything missing or invalid.
WebDAV credential values can also live outside config.toml in
noteui/secrets.toml inside the user config directory. That file is separate
from the config file, and NOTEUI_CONFIG does not change its location. See
Environment variables for the
full lookup and file-format rules.
Splitting the config across files¶
config.toml can pull in additional TOML files through the [meta] table:
Each entry is a path to another TOML file that uses the same keys as config.toml:
- absolute paths are used as-is
- paths starting with
~/expand to your home directory - relative paths resolve against the directory of the main config file; by default that is
noteui/inside the user config directory, and ifNOTEUI_CONFIGpoints somewhere else, relative includes move with it
noteui reads the main file first, then each include in the order it appears in includes. When the same key is set in more than one file, the last file to set it wins. Named tables such as [workspaces.<name>] and [sync.profiles.<name>] accumulate entries across files, so the main file and an include can each contribute their own workspaces and sync profiles.
Rules and behavior:
- A missing include file is a startup warning, not an error. A shared
config.tomlstays usable on a machine where the private include does not exist yet. - Duplicate and empty
includesentries are skipped with a warning. - Only the main config file may contain
[meta]. An included file with its own[meta]table is rejected, so includes cannot include further files. - Validation runs on the merged result, so a key in one file may reference something defined in another. Keep
sync.default_profilein the same file as the profiles it names; otherwise the config fails validation on machines missing that include. - Errors in an included file (invalid TOML, unknown keys) are reported with that file's path.
The common use is keeping private settings out of a shared dotfiles repo: commit config.toml, list a gitignored local.toml in includes, and keep [sync] profiles and private workspace roots there. See Split config for dotfiles for a full walkthrough. noteui +check-config validates the merged result and prints include warnings.
What noteui writes back¶
Defaults live in code. noteui does not rewrite your config.toml with every default value.
Today, in-app writes are intentionally narrow:
- the theme picker and
noteui +set-themeupdate onlytheme.name; any existingtheme.*_coloroverrides remain in place - the in-app sync profile picker updates only
sync.default_profile - the in-app editor command
:set rnu/:set nornuupdates onlypreview.relative_line_numbers
When noteui writes one of those values, it patches that key in place and preserves the rest of the file where possible instead of reformatting the whole config.
When the config is split with [meta] includes, an in-app write targets the file whose value currently wins: if you defined the key in an included file, noteui updates that included file rather than the main config.toml, so the change is not shadowed on the next launch. If no file defines the key yet, the new value is written to the main config.toml. When you reset a value to its default (for example switch back to the default theme), noteui removes the key from every file that defined it, so the built-in default takes effect instead of an earlier definition winning.
Included files that live outside the config directory (absolute or ~/ paths) are edited in place too, so a key you keep in a git-tracked dotfiles include will show up as a change in that file after an in-app edit.
Minimal example¶
dashboard = true
default_workspace = "work"
[workspaces.work]
root = "/home/alice/notes"
label = "Work"
[workspaces.demo]
root = "/home/alice/demo-notes"
label = "Demo"
[theme]
name = "nord"
[preview]
style = "auto"
[sync]
default_profile = "homebox"
[sync.profiles.homebox]
ssh_host = "notes-prod"
remote_root = "/srv/noteui"
remote_bin = "/usr/local/bin/noteui-sync"
Full example¶
dashboard = true
default_workspace = "work"
[workspaces.work]
root = "/home/alice/notes"
label = "Work"
sync_remote_root = "/srv/noteui/work"
[workspaces.demo]
root = "/home/alice/demo-notes"
label = "Demo"
sync_remote_root = "/srv/noteui/demo"
[theme]
name = "default"
border_style = "rounded"
app_padding_x = 2
app_padding_y = 1
panel_padding_x = 1
panel_padding_y = 0
[typography]
bold_title_bar = true
bold_panel_titles = true
bold_headers = true
bold_selected = true
bold_modal_titles = true
[icons]
category_expanded = "▾"
category_collapsed = "▸"
category_leaf = "•"
note = "·"
[modal]
border_style = "rounded"
padding_x = 2
padding_y = 1
[preview]
render_markdown = true
style = "dark"
syntax_highlight = true
code_style = "monokai"
privacy = false
line_numbers = true
mouse_scroll_step = 3
edit_in_preview = false
[sync]
default_profile = "homebox"
[sync.profiles.homebox]
kind = "ssh"
ssh_host = "notes-prod"
remote_root = "/srv/noteui"
remote_bin = "/usr/local/bin/noteui-sync"
[sync.profiles.cloud]
kind = "webdav"
webdav_url = "https://cloud.example.com/remote.php/dav/files/alice"
remote_root = "/Notes"
auth = "basic"
username_env = "NOTEUI_WEBDAV_USER"
password_env = "NOTEUI_WEBDAV_PASSWORD"
[keys]
toggle_sync = ["S"]
select_workspace = ["W"]
select_sync_profile = ["F"]
open_conflict_copy = ["O"]
show_sync_debug = ["ctrl+e"]
show_sync_timeline = ["Y"]
delete_remote_keep_local = ["U"]
sync_import_current = ["i"]
sync_import = ["I"]
Top-level keys¶
dashboarddefault_workspaceworkspacesmetathemetypographyiconsmodalpreviewkeyssyncdaily_notes
dashboard¶
Type: boolean
Default:
Controls whether the dashboard is enabled.
default_workspace¶
Type: string
Optional. When set, noteui starts in that configured workspace. The name must match a key under workspaces.
workspaces¶
Type: table of named workspace entries
Each workspace defines a notes root and an optional display label.
Example:
[workspaces.work]
root = "/home/alice/notes"
label = "Work"
[workspaces.demo]
root = "/home/alice/demo-notes"
label = "Demo"
Supported keys per workspace:
root: required notes root for that workspacelabel: optional UI label used in the footer, title bar, and pickersync_remote_root: optional path override that directs sync traffic for this workspace to a specific remote directory, instead of using the active sync profile'sremote_root
sync_remote_root is the key to preventing cross-workspace note contamination when multiple workspaces share the same sync profile. Without it, all workspaces upload to and download from the same remote directory, which means workspace A's notes appear as remote-only placeholders in workspace B.
For SSH profiles, sync_remote_root is a normal remote filesystem path such as /srv/noteui/work.
For WebDAV profiles, sync_remote_root is still a remote path, but it is relative to the configured webdav_url. In other words, use values such as /Notes/work or /Notes/personal, not local filesystem paths like /home/alice/notes/work.
Example with per-workspace remote roots:
[workspaces.work]
root = "/home/alice/notes/work"
label = "Work"
sync_remote_root = "/srv/noteui/work"
[workspaces.personal]
root = "/home/alice/notes/personal"
label = "Personal"
sync_remote_root = "/srv/noteui/personal"
When sync_remote_root is set, the workspace picker shows it as a third line under the root path so you can confirm the mapping before switching.
Workspace switching is available from the command palette when multiple workspaces are configured. Local UI state such as pins, collapsed folders, recent commands, and sort preference is stored separately per workspace.
meta¶
Type: table
Controls how the configuration itself is loaded. The only key is includes, a list of extra TOML files merged over the main config file. See Splitting the config across files for resolution and precedence rules.
[meta] is only allowed in the main config file, not in included files.
theme¶
Theme chooses the built-in theme and optional visual overrides.
preview¶
Preview controls markdown rendering, syntax highlighting, privacy behavior, line numbers, and mouse-wheel scrolling in the preview pane.
preview.render_markdown¶
Type: boolean
Default:
Controls whether note bodies are rendered as Markdown in the preview pane. When disabled, noteui shows plain text.
preview.disable_paths¶
Type: array of strings
Default:
Optional path patterns where Markdown rendering should be disabled even when render_markdown is enabled.
preview.style¶
Type: string
Default:
Controls the Markdown renderer style. Valid values are dark, light, auto, and notty.
preview.syntax_highlight¶
Type: boolean
Default:
Controls syntax highlighting for fenced code blocks in rendered Markdown previews.
preview.code_style¶
Type: string
Default:
Controls the code highlighting theme used in the preview renderer.
preview.privacy¶
Type: boolean
Default:
When enabled, preview content starts in blurred privacy mode.
preview.line_numbers¶
Type: boolean
Default:
Controls whether the preview shows line numbers by default.
preview.mouse_scroll_step¶
Type: integer
Default:
Controls how many preview rows each mouse-wheel step scrolls. The value must be at least 1.
preview.edit_in_preview¶
Type: boolean
Default:
When enabled, the in-app editor opened with e stays inside the preview pane. When disabled, the in-app editor takes over the full screen.
[editor]¶
editor.fullscreen¶
Type: boolean
Default:
When true, the in-app editor always opens in full-screen mode regardless of preview.edit_in_preview. The ctrl+f keybind toggles full-screen on and off for the current session, overriding this default.
theme.name¶
Type: string
Default:
Use ctrl+y in the TUI to open the theme picker. Press / or tab there to filter themes by name, alias, or description before saving theme.name.
Valid built-in theme names:
defaultnordgruvboxcatppuccincatppuccin-mochamochacatppuccin-lattelattesolarized-lightpaperonedarkkanagawadraculaeverforesteverforest-darktokyo-night-stormtokyonight-stormgithub-lightgithub-darkcarbonfoxcrimsonduskrose-pinerosepinerose_pinemonokaisolarized-darksolarizedayu-darkayumaterialmaterial-darknightfoxmonochromemonochrome-light
Theme color overrides¶
Type: string for each field
Supported override fields:
bg_colorpanel_bg_colorborder_colorfocus_border_coloraccent_coloraccent_soft_colortext_colormuted_colorsubtle_colorchip_bg_colorinline_code_bg_colorpinned_note_colorsynced_note_colorunsynced_note_colorsyncing_note_colorshared_note_colormarked_item_colorerror_colorsuccess_colorselected_bg_colorselected_fg_colorhighlight_bg_color
These fields default to the selected built-in theme. Leave them unset unless you want to override a specific color.
noteui keeps these overrides active when you change theme.name from the theme picker or via noteui +set-theme. If an override would make text too low-contrast against its background, noteui adjusts the final rendered color slightly so the interface stays readable.
theme.border_style¶
Type: string
Default:
Valid values:
roundednormaldoublethickhidden
Theme spacing¶
Type: integer
Defaults:
These fields control outer app padding and per-panel padding.
typography¶
Type: booleans
Defaults:
[typography]
bold_title_bar = true
bold_panel_titles = true
bold_headers = true
bold_selected = true
bold_modal_titles = true
Supported fields:
bold_title_barbold_panel_titlesbold_headersbold_selectedbold_modal_titles
icons¶
Type: strings
Defaults:
Supported fields:
category_expandedcategory_collapsedcategory_leafnote
modal¶
Modal controls popup colors, border style, and padding.
Supported fields:
bg_colorborder_colortitle_colortext_colormuted_coloraccent_colorerror_colorborder_stylepadding_xpadding_y
Fields left unset inherit the app's effective visual styling.
Defaults:
Valid modal.border_style values match theme.border_style.
preview¶
Preview controls terminal preview rendering.
Defaults:
[preview]
render_markdown = true
style = "dark"
syntax_highlight = true
code_style = "monokai"
privacy = false
line_numbers = true
edit_in_preview = false
preview.render_markdown¶
Type: boolean
When true, noteui renders Markdown-style previews for supported note content.
preview.disable_paths¶
Type: list of strings
Default: unset
Use this to turn off rich preview rendering for specific paths or subtrees.
Example:
preview.style¶
Type: string
Valid values:
darklightautonotty
preview.syntax_highlight¶
Type: boolean
Enables syntax highlighting inside rendered code blocks.
preview.code_style¶
Type: string
Supported values:
monokaigithubdraculaswapoffonesenterprisenativeparaiso-darkparaiso-light
preview.privacy¶
Type: boolean
Controls privacy blur mode in the preview pane.
preview.line_numbers¶
Type: boolean
Controls line numbers in the preview pane.
preview.relative_line_numbers¶
Type: boolean
When true, the in-app editor shows line numbers as distances from the cursor (relative numbers) rather than absolute line numbers. The cursor line always shows its absolute number. Can also be toggled at runtime with :set rnu / :set nornu inside the editor; the setting is written back to this key automatically.
preview.edit_in_preview¶
Type: boolean
Controls whether the in-app editor opened with e renders inside the preview pane instead of taking over the full screen.
sync¶
Sync is optional. If sync.default_profile is empty, noteui does not attempt network sync.
sync.default_profile¶
Type: string
Default: empty
If set, it must match one of the names under sync.profiles.
sync.profiles.<name>¶
Each sync profile has a kind field that selects the backend. When kind is omitted, it defaults to "ssh".
SSH profiles (kind = "ssh")¶
| Key | Required | Default | Description |
|---|---|---|---|
kind |
no | "ssh" |
Backend type |
ssh_host |
yes | SSH host to connect to | |
remote_root |
yes | Remote directory for sync data | |
remote_bin |
no | "noteui-sync" |
Path to noteui-sync on remote |
Example:
[sync.profiles.homebox]
kind = "ssh"
ssh_host = "notes-prod"
remote_root = "/srv/noteui"
remote_bin = "/usr/local/bin/noteui-sync"
WebDAV profiles (kind = "webdav")¶
| Key | Required | Default | Description |
|---|---|---|---|
kind |
yes | Must be "webdav" |
|
webdav_url |
yes | Full URL to the authenticated WebDAV user endpoint (http:// or https://) |
|
remote_root |
no | "/noteui" |
Remote directory under webdav_url where noteui stores notes and metadata |
auth |
no | "basic" |
Auth mode: "basic", "bearer", or "none" |
username_env |
when auth=basic | Env var name holding the username value | |
password_env |
when auth=basic | Env var name holding the password value | |
token_env |
when auth=bearer | Env var name holding the bearer token value (e.g. a Nextcloud app token or OAuth access token) | |
force_ipv4 |
no | false |
Force all connections to use IPv4. Use when the server's IPv6 path resets connections while IPv4 works (common with Nextcloud behind a reverse proxy that is only bound to IPv4). |
insecure_skip_tls_verify |
no | false |
Disable TLS certificate verification. Use only on trusted internal networks where the server has a self-signed or IP-only certificate. noteui warns at startup while this is active on an https:// profile, since the connection is then exposed to man-in-the-middle attacks; prefer ca_cert. |
ca_cert |
no | Path to a PEM-encoded CA certificate file to trust in addition to system CAs. Use for internal servers signed by a private CA. |
Example:
[sync.profiles.cloud]
kind = "webdav"
webdav_url = "https://cloud.example.com/remote.php/dav/files/alice"
remote_root = "/Notes/personal"
auth = "basic"
username_env = "NOTEUI_WEBDAV_USER"
password_env = "NOTEUI_WEBDAV_PASSWORD"
Practical rules:
webdav_urlshould usually stop at the user endpoint. For Nextcloud that is typicallyhttps://<host>/remote.php/dav/files/<username>.remote_rootis joined under that endpoint. If you want noteui to sync into a Nextcloud folder namedNotes, useremote_root = "/Notes".- Do not append the notes folder to
webdav_urland repeat it again inremote_root. username_env,password_env, andtoken_envare variable names, not the secrets themselves. noteui checks those names in the current environment first, then innoteui/secrets.tomlinside the user config directory if the env vars are empty or missing.NOTEUI_CONFIGonly changesconfig.tomllookup. It does not movesecrets.toml.- noteui creates
remote_rootand its.noteui-sync/metadata directory automatically on first successful upload. - if you use
sync_remote_rootwith a WebDAV profile, it follows the same semantics asremote_root.
For end-to-end sync setup, import flows, conflict resolution, and recovery behavior, see the Sync guide.
keys¶
Each [keys] field takes a list of key strings.
If a field is omitted or given an empty list, noteui keeps the built-in default binding.
Example:
[keys]
open = ["enter", "o"]
toggle_sync = ["S"]
open_conflict_copy = ["O"]
sync_import = ["I"]
note_history = ["H"]
trash_browser = ["X"]
Everyday navigation and panes¶
openDefault:["enter", "o"]edit_in_appDefault:["e"]Opens the selected note in the in-app editor. The external editor path onopenis unchanged. Usepreview.edit_in_previewto keep that editor inside the preview pane.refreshDefault:["r"]quitDefault:["q", "ctrl+c"]focusDefault:["tab"]searchDefault:["/"]command_paletteDefault:["ctrl+p", ":"]move_upDefault:["k", "up"]move_downDefault:["j", "down"]collapse_categoryDefault:["h", "left"]expand_categoryDefault:["l", "right"]jump_bottomDefault:["G"]pending_gDefault:["g"]scroll_half_page_upDefault:["ctrl+u"]scroll_half_page_downDefault:["ctrl+d"]scroll_page_downDefault:["ctrl+f", "pgdown"]scroll_page_upDefault:["ctrl+b", "pgup"]next_matchDefault:["n"]prev_matchDefault:["N"]
Notes, categories, and organization¶
new_noteDefault:["n"]new_temporary_noteDefault:["N"]new_todo_listDefault:["T"]create_categoryDefault:["C"]toggle_categoryDefault:[" "]deleteDefault:["d"]moveDefault:["m"]renameDefault:["R"]add_tagDefault:["A"]remove_tagDefault:["K"]toggle_selectDefault:["v"]clear_marksDefault:["V"]pinDefault:["p"]promote_temporaryDefault:["M"]archive_temporaryDefault:["ctrl+a"]move_to_temporaryDefault:["ctrl+r"]show_pinsDefault:["P"]show_todosDefault:["ctrl+t"]select_workspaceDefault:["W"]sort_keyDefault:["s"]Opens the sort menu. Follow with a sub-key to pick a method.sort_by_nameDefault:["n"]Active only inside the sort menu. Sorts alphabetically by path.sort_by_modifiedDefault:["m"]Active only inside the sort menu. Sorts by modification time, newest first.sort_by_createdDefault:["c"]Active only inside the sort menu. Sorts by creation date (frontmatterdate:/created:/created-at:, falling back to modification time), newest first.sort_by_sizeDefault:["s"]Active only inside the sort menu. Sorts by file size, largest first.sort_reverseDefault:["r"]Active only inside the sort menu. Toggles ascending/descending order.
Preview and help¶
show_helpDefault:["?"]toggle_preview_privacyDefault:["B"]toggle_preview_line_numbersDefault:["L"]
Sync¶
toggle_syncDefault:["S"]Toggles the selected local note betweensync: localandsync: synced.make_sharedDefault:["ctrl+s"]Toggles the selected note betweensync: sharedandsync: local.select_sync_profileDefault:["F"]open_conflict_copyDefault:["O"]Opens the generated conflict copy for the selected conflicted synced note.show_sync_debugDefault:["ctrl+e"]Opens the sync details modal for the selected unhealthy synced note.show_sync_timelineDefault:["Y"]Opens the sync timeline showing recent sync run history for the current workspace.delete_remote_keep_localDefault:["U"]sync_import_currentDefault:["i"]sync_importDefault:["I"]undo_deleteDefault:["Z"]Restores the most recently trashed note or category to its original path. Available until the next deletion or workspace switch.
History and extra motions¶
note_historyDefault:["H"]Opens the version history modal for the selected local note.trash_browserDefault:["X"]Opens the trash browser modal, listing notes trashed from the current workspace. Navigate withj/k, pressenterto restore,escto close.
Templates¶
new_templateDefault:["ctrl+n"]Creates a blank template file in.templates/and opens it in your editor.edit_templatesDefault:["ctrl+k"]Opens the template picker in edit mode so you can select a template to edit.
Daily notes¶
open_daily_noteDefault:["D"]Opens today's daily note, creating it if it does not yet exist. See[daily_notes]for directory and template configuration.
Todo and extra motions¶
bracket_forwardDefault:["]"]bracket_backwardDefault:["["]heading_jump_keyDefault:["h"]todo_keyDefault:["t"]todo_addDefault:["a"]todo_deleteDefault:["d"]todo_editDefault:["e"]todo_due_dateDefault:["u"]todo_priorityDefault:["p"]pending_zDefault:["z"]delete_confirmDefault:["d"]toggle_encryptionDefault:["E"]link_keyDefault:["f"]Second key of the]f/[fchord to enter link nav mode in the preview pane. Also follows the selected link when already in link nav mode.follow_linkDefault:["f"]Follows (opens) the currently selected wikilink while in link nav mode. Shares the default withlink_key.
The in-app help modal is still the live source of truth if you change keybindings heavily.
noteui +check-config validates both direct key collisions and ambiguous chord families such as sort-menu sub-keys, ] / [ preview chords, and todo_key follow-up actions.
[keys]¶
The [keys] section overrides default bindings.
Sync-related key defaults:
toggle_sync = ["S"]make_shared = ["ctrl+s"]select_workspace = ["W"]select_sync_profile = ["F"]open_conflict_copy = ["O"]show_sync_debug = ["ctrl+e"]show_sync_timeline = ["Y"]delete_remote_keep_local = ["U"]sync_import_current = ["i"]sync_import = ["I"]
[daily_notes]¶
Controls where daily notes are stored and which template is used when creating one.
daily_notes.dir¶
Type: string
Default: "daily"
The subdirectory inside your notes root where daily notes are stored. The directory is created automatically on first use.
daily_notes.template¶
Type: string
Default: "" (no template; a minimal heading is used instead)
Path to a template file relative to .templates/. When set, pressing D creates the daily note by applying that template (with {{date}}, {{time}}, and {{title}} substitution). When empty, the note is created with a # YYYY-MM-DD heading.
Example:
With this config, pressing D opens or creates journal/YYYY-MM-DD.md, using .templates/daily.md as the template for new files.
Reserved directories¶
noteui uses the following hidden directories inside the notes root and skips them during normal note discovery:
| Directory | Purpose |
|---|---|
.tmp/ |
Temporary notes |
.noteui-history/ |
Automatic per-note version history |
.noteui-sync/ |
Sync bookkeeping metadata and event log (sync-events.jsonl) |
.templates/ |
User-defined note templates (see Note templates) |