Vim Motions has built-in vimrc support, compatible with obsidian-vimrc-support syntax. When both plugins are installed, they coexist — Vim Motions registers its own :ob command independently.
Lua configuration available
Vim Motions also supports Lua configuration with Neovim-compatible syntax. Lua config provides conditional logic and function-based keymaps. See lua-config for details.
File location
The plugin searches the vault root for the first matching file in this order:
vimrc.vimrcinit.vim.init.vimobsidian.vimrcobsidian.vim.obsidian.vimrc.obsidian.vim
The first file found is used. Override this with a custom path in Settings → Vim Motions → Vimrc & key bindings → Custom vimrc path. The settings UI shows which file is currently active.
Shared config across vaults (desktop only)
Two ways to share one vimrc across multiple vaults on desktop:
Option A — Global config search toggle: Enable Settings → Vim Motions → Vimrc & key bindings → Search global config directory. The plugin will automatically search the Obsidian user data folder after exhausting vault-root candidates:
~/.config/obsidian/(Linux)~/Library/Application Support/obsidian/(macOS)%APPDATA%\obsidian\(Windows)
Place your vimrc (or any file from the fallback chain) in the appropriate directory and it will be found automatically. Vault-root files always take priority.
Option B — Custom absolute path: Set an absolute path in Settings → Vim Motions → Vimrc & key bindings → Custom vimrc path:
~/.config/obsidian/vimrc(Linux)~/Library/Application Support/obsidian/vimrc(macOS)C:\Users\<you>\.config\obsidian\vimrc(Windows)
Any path starting with /, ~, or a drive letter is read directly from the filesystem instead of through the vault.
Neither option is available on mobile.
Obsidian Sync
Obsidian Sync skips dotfiles. Use a non-dotfile name like
vimrc(the first candidate in the fallback chain) to ensure your config syncs across devices.
Example vimrc
" Leader key
let mapleader = " "
" Key mappings
nnoremap j gj
nnoremap k gk
" Settings (override Settings UI values)
set scrolloff=5
set textwidth=80
set clipboard=unnamed
set expandtab
set tabstop=4
set shiftwidth=2
set insertmodeescape=jk
set insertmodeescapetimeout=1000
set easymotion
set nopowerline
set easymotionlabels=asdghklqwertyuiopzxcvbnmfj
" Cursor shapes (bundled engine or Neovim backend; not built-in vim mode)
set guicursor=n:block,i:bar,v:block,r:underline,o:underline
" Mode prompts
let g:mode_prompt_normal = "N"
let g:mode_prompt_insert = "I"
" Leader key mappings
exmap saveFile obcommand editor:save-file
nmap <leader>w :saveFile<CR>
" Which-key labels
whichkeygroup <leader>t Table
whichkeylabel <leader>w Save file
" Global mappings (non-editor contexts)
gmap <leader>f :obcommand switcher:open
gmap <leader>e :obcommand file-explorer:reveal-active-file
gnoremap <leader>s :sidebar left
gunmap H
" Global which-key labels
gwhichkeygroup <leader> +leader
gwhichkeylabel <leader>f Open file
" Custom surround pairs
surroundmap l [[ ]]
surroundmap m $$ $$
" Override a built-in pair: `ysiw(` wraps as `(word)`, not `( word )`
surroundmap ( ( )Built-in surround characters can be overridden. Removing the surroundmap line
and reloading restores the built-in — see
surround > Overriding the built-in pairs for the three characters whose
interactive behaviour an override replaces.
Supported commands
| Command | Description |
|---|---|
map / nmap / imap / vmap | Mode-specific key mappings |
noremap / nnoremap / inoremap / vnoremap | Non-recursive mappings |
unmap / nunmap / iunmap / vunmap | Remove mappings |
set | Set plugin options (see tables below) |
let mapleader | Set the leader key |
exmap | Define a named command from an Obsidian command |
obcommand | Execute an Obsidian command by ID (alias of :ob) |
source | Source another vimrc file |
gmap / gnoremap | Global key mapping for non-editor contexts |
gunmap | Remove a global mapping |
whichkeygroup | Name a which-key group by prefix |
whichkeylabel | Label an individual binding in which-key |
gwhichkeygroup | Name a global which-key group by prefix |
gwhichkeylabel | Label a global binding in which-key |
surroundmap | Register a surround pair, or override a built-in |
surroundunmap | Remove a surround pair, restoring any built-in |
Leader key
let mapleader supports any key: space (let mapleader = " "), comma, semicolon, backslash (default). The leader key’s default Vim binding is automatically unmapped so leader-prefixed sequences work correctly.
Boolean options
Use set <option> to enable, set no<option> to disable.
| Option | Alias | Description | Default |
|---|---|---|---|
textobjects | to | Markdown-aware text objects | on |
replacewithregister | rwr | Replace-with-register operator | on |
navigation | nav | Heading, list, and link navigation | on |
hardwrap | hw | gq/gw hard-wrap operators | on |
listcontinuation | lc | Smart list continuation on o/O | on |
tablenav | tn | Table cell navigation | on |
workspacenav | wn | Pane/tab/sidebar control | on |
number | nu | Show absolute line numbers | off |
relativenumber | rnu | Show relative line numbers | off |
flash | — | Flash-style f/F/t/T labels | on |
flashmultiline | fml | Flash searches beyond current line | on |
flashjump | — | Flash bidirectional jump mode (s) | off |
flashcleverf | — | Clever-f repetition | off |
flashsearch | — | Labels on /? search matches | on |
labelmatchfontsize | lmfs | Scale labels to match line font size | off |
easymotion | em | EasyMotion/Hop navigation | on |
easymotiondimming | emd | Dim non-target text during EasyMotion | on |
hintmode | hm | Vimium-style hint labels | on |
statusbar | sb | Vim mode in status bar | on |
chorddisplay | cd | Pending keystrokes in status bar | on |
powerline | pl | Colored powerline status bar | off |
expandtab | et | Use spaces instead of tabs | on |
pcre | — | Use JavaScript regexps in search/subst | on |
cursorline | cul | Cursor line highlight | on |
foldcolumn | fdc | Fold column indicators | off |
markgutter | — | Alias for signcolumn (compat) | on |
snippets | — | Enable snippet expansion | on |
snippetbundled | — | Include bundled Obsidian snippets | on |
vimtextareas | vta | Vim keybindings in text areas | off |
yankring | — | Yank-ring paste cycling | on |
harpoon | — | Harpoon file pinning | on |
dial | — | Enhanced increment/decrement | off |
jumplist | — | Vim-style jump list for <C-o>/<C-i> | on |
foldawarenavigation | — | Master toggle for fold-aware navigation | on |
foldpersistence | — | Persist fold state across sessions | off |
undotree | ut | Enable undo tree tracking | on |
undofile | udf | Persist undo tree across sessions | off |
smoothcursor | sc | Enable animated cursor | off |
smoothcursorglide | scg | Smooth cursor movement (glide) | on |
smoothcursorsmear | scm | Enable smear trail | on |
subword | — | Spider.nvim-style subword motions | off |
picker | — | Telescope-style picker | on |
pickerleadermappings | — | Leader key picker shortcuts | on |
pickeromnisearch | — | Omnisearch picker integration | off |
pickertasks | — | Obsidian Tasks picker integration | off |
pickerdataview | — | Dataview picker integration | off |
ripgrep | — | Use ripgrep binary for grep | off |
oil | — | Oil file explorer | off |
oilhiddenfiles | — | Show hidden files in Oil | off |
undotreeautoopen | — | Auto-open undo tree on branch | off |
imswitching | — | Input method auto-switching | off |
ignorecase | ic | Case-insensitive search | on |
smartcase | scs | Override ignorecase when query has uppercase | on |
hlsearch | hls | Highlight all search matches | on |
incsearch | is | Incremental search while typing | on |
wrapscan | ws | Search wraps around document | on |
gdefault | gd | :s defaults to global replace | off |
startofline | sol | Vertical motions go to first non-blank | on |
joinspaces | js | J inserts two spaces after .!? | off |
shiftround | sr | >>/<< round to shiftwidth multiple | off |
Number options
Use set <option>=<value>.
| Option | Alias | Description | Default | Range |
|---|---|---|---|---|
scrolloff | so | Lines to keep visible above/below cursor | 5 | 0-9999 |
scanlimit | sl | Max lines to scan for text objects | 20 | 5-200 |
labelfontsize | lfs | Font size for EasyMotion/hint labels | 14 | 10-20 |
tabstop | ts | Tab display width | 4 | 1-8 |
shiftwidth | sw | Indent width | 4 | 1-8 |
textwidth | tw | Line wrap width for gq/gw | 80 | 0-200 |
insertmodeescapetimeout | imet | Timeout (ms) for insert escape sequence | 1000 | 100-5000 |
operatorshadowtimeout | ost, timeoutlen, tm | Timeout (ms) for operator-prefix and mapping-prefix disambiguation (equivalent to Neovim’s timeoutlen) | 1000 | 0-5000 |
numberwidth | nuw | Minimum line number column width | 2 | 1-20 |
jumplistsize | — | Maximum jump list entries | 200 | 1-1000 |
undotreemaxnodes | utmn | Maximum undo tree nodes per file | 1000 | 100-5000 |
yankhighlightduration | — | Yank highlight duration (ms) | 200 | 0-5000 |
smoothcursorsmoothness | scs | Cursor movement smoothness | 0.5 | 0-1 |
smoothcursorstiffness | scst | Smear trail head stiffness | 0.6 | 0.1-1 |
smoothcursortrailstiffness | scts | Smear trail tail stiffness | 0.3 | 0.1-1 |
smoothcursordamping | scd | Smear trail velocity decay | 0.85 | 0.1-0.99 |
smoothcursormaxlength | scml | Maximum smear trail length (px) | 400 | 50-800 |
oilconfirmdeletethreshold | — | Oil delete confirmation threshold | 1 | 0-100 |
String options
Use set <option>=<value>.
| Option | Alias | Description | Default |
|---|---|---|---|
clipboard | clip | System clipboard sync (unnamed/unnamedplus) | (off) |
foldopen | fdo | Motion categories that auto-unfold (Neovim-compatible) | block,hor,mark,percent,search,undo |
insertmodeescape | ime | Two-key sequence to exit insert mode | (off) |
flashjumpkey | — | Key to trigger flash jump mode | s |
flashminpatternlength | fmpl | Minimum chars before labels in jump mode | 1 |
yankhighlightmode | — | Yank highlight style (off/solid/fade) | solid |
easymotionlabels | eml | Characters for EasyMotion and flash labels | asdghklqwertyuiopzxcvbnmfj |
hintlabels | hl | Characters for hint mode labels | asdfghjkl |
guicursor | — | Per-mode cursor shapes | (block/bar/block/underline/underline) |
tablewidget | — | Table widget mode (native/owned/raw). raw is deprecated — it hides the table without showing its source; use Source mode. owned is experimental | native |
whichkey | wk | Which-key hints (off/leader/all) | off |
whichkeygrouping | wkg | Which-key grouping (flat/grouped) | grouped |
whichkeysort | wks | Which-key sort order (which-key/groups-first) | which-key |
whichkeyicons | wki | Which-key icons (on/off) | on |
workspacenavviewtypes | wnvt | View types for workspace nav interception | (empty — uses defaults: markdown, graph, pdf, canvas, empty, image, bases) |
cursorlineopt | culopt | Cursor line highlight mode (number/line/screenline/both/screenline,number; comma lists accepted) | both |
signcolumn | scl | Sign column visibility (auto[:N]/yes[:N]/no) | auto |
linenumbermode | lnm | Line number display (deprecated — use statuscolumn) | hybrid |
statuscolumn | stc | Custom gutter layout format string | (empty — plugin-managed) |
snippetdir | — | Path to user snippet JSON directory | (off) |
snippettrigger | — | Snippet trigger mode (completion/tab/both) | both |
pickermatcher | — | Picker match engine (ufuzzy/obsidian) | ufuzzy |
pickerpreview | — | Non-Markdown picker previews (rendered/hidden/raw) | rendered |
ripgreppath | — | Path to ripgrep binary | (off) |
ripgrepargs | — | Additional ripgrep arguments | (off) |
grepmode | — | Grep backend (ripgrep/grep) | ripgrep |
oilsort | — | Oil default sort (name/mtime/size) | name |
hinthotkey | — | Key to trigger hint mode | (off) |
undotreeposition | — | Undo tree sidebar position (left/right) | right |
impreset | — | IM preset (custom/macism/im-select/fcitx5-remote/ibus) | custom |
imbinarypath | — | Path to IM binary | (off) |
imobtainargs | — | Args for obtaining current IM | (off) |
imswitchargs | — | Args for switching IM | {im} |
imdefaultnormal | — | Default IM for normal mode | (off) |
imrestorebehavior | — | IM restore behavior (restore/default) | restore |
imdefaultinsert | — | Default IM for insert mode | (off) |
whichwrap | ww | Keys that wrap to next/prev line at boundaries (h,l,b,s,<,>) | b,s |
virtualedit | ve | Cursor past EOL (onemore/all/block/insert) | (off) |
nrformats | nf | Number formats for <C-a>/<C-x> (bin,hex,octal) | bin,hex |
Mode prompt customization
let g:mode_prompt_normal = "N"
let g:mode_prompt_insert = "I"
let g:mode_prompt_visual = "V"
let g:mode_prompt_replace = "R"Which-key labels
" Group labels — collapse bindings under a named prefix
whichkeygroup <leader>t Table
whichkeygroup <leader>g Git
" Command labels — describe individual bindings
whichkeylabel <leader>w Save file
whichkeylabel gd Go to definitionGroup and command labels from vimrc are merged with labels configured in Settings. If the same key appears in both, the vimrc value takes precedence.
Remapping <Esc>
imap/inoremap and vmap/vnoremap work for <Esc>, and your mapping wins over the built-in mode exit:
" Leave insert mode and clear the search highlight
inoremap <Esc> <Esc>:noh<CR>
" Leave visual mode two columns to the right
vnoremap <Esc> llOnly an exact <Esc> mapping takes over. A longer one such as inoremap <Esc>q ZZ leaves bare <Esc> exiting insert mode as usual, so binding a prefix cannot strand you in insert mode. <C-[> follows your <Esc> mapping because it is the same key, while <C-c> does not — which makes <C-c> a dependable way out whatever you bind. See known-limitations > Only an exact Escape mapping overrides the built-in mode exit.
Use :stopinsert to leave insert mode from a mapping or Lua callback without sending a key. See ex-commands > stopinsert—stopi—leave-insert-mode.
Global key mappings
gmap and gnoremap define key bindings for non-editor contexts — graph view, canvas, PDF viewer, reading mode, file explorer, and any other view where no editor is focused. These bindings use the same <leader> key as editor mappings.
" Map <leader>f to open the quick switcher in non-editor views
gmap <leader>f :obcommand switcher:open
" Map <leader>e to reveal the active file in the explorer
gmap <leader>e :obcommand file-explorer:reveal-active-file
" Map a key to an ex command
gnoremap <leader>s :sidebar left
" Remove a default global binding
gunmap HThe right-hand side must be either :obcommand <command-id> (to execute an Obsidian command) or :<ex-command> [args] (to execute a global ex command like :sidebar, :split, :grep, etc.). Key-to-key remapping is not supported in global context.
gnoremap is functionally identical to gmap — both are accepted for familiarity with Vim syntax.
Use gunmap to remove any global binding, including built-in defaults like H (previous tab) or L (next tab). After gunmap, the key is no longer intercepted and propagates to Obsidian’s native handlers.
:gmap and :gunmap also work from the editor’s : command line:
:gmap H :files
:gunmap L
:gmaps " list all active global bindingsGlobal which-key labels
Label your global bindings for the non-editor which-key overlay:
gwhichkeygroup <leader> +leader bindings
gwhichkeylabel <leader>f Open file
gwhichkeylabel <leader>e Reveal in explorerThese labels appear in the which-key overlay when a partial global key sequence is pending (e.g., pressing <leader> in a non-editor view shows all <leader>* global bindings).
Override behavior
When configuration mode includes vimrc (Lua + Vimrc or Vimrc only), vimrc values override the corresponding Settings UI values for the current session. Overrides are persisted in a configOverrides block in data.json so they survive Obsidian restarts. The base settings always reflect UI-set values — configOverrides captures the last-known vimrc/Lua values and merges them on top at startup.
Settings overridden by vimrc appear as disabled controls in the settings tab with a note showing the vimrc directive (e.g., “Set by vimrc: set scrolloff=10”). Changing a setting via the Settings UI clears the override for that key.
Gutter settings apply immediately
Settings that control CM6 gutter extensions (
number,relativenumber,signcolumn,foldcolumn,cursorline,statuscolumn) take effect as soon as the config file is loaded, matching the Settings UI. These extensions are registered once at startup inside CodeMirror compartments, which are then reconfigured in place. Earlier releases required one Obsidian restart, because that reconfiguration resolved the wrong editor property and so reached no open editor.
Settings not available via vimrc
| Setting | Reason |
|---|---|
configMode | Circular dependency — cannot control config file loading from vimrc |
leaderBindings | Already achievable via nmap <leader>x :command in vimrc |
pickerKeymap | Complex array-valued keys — not suited for :set syntax |
Every Neovim option is recognized by name — typos produce a warning (set mose=a warns) while Neovim options that are not applicable in Obsidian are accepted silently (set mouse=a, set encoding=utf-8, set noswapfile). Options that exist but are not yet configurable log an info-level note explaining the current behavior.
Soft-reload
The vimrc file is watched for changes. When you save the file, nmap, set, exmap, and other commands are re-applied without reloading the plugin. Adding, modifying, or removing exmap definitions all take effect on save — the fork’s undefineEx() API cleans up stale handlers automatically.
You can also manually trigger a reload of all configuration files (both vimrc and Lua) using the Vim Motions: Reload configuration command from the Obsidian command palette.
External editor (desktop only)
On desktop, you can open your active configuration files in your system’s default external editor using the Vim Motions: Open configuration in default editor command. This will open both .obsidian.vimrc and init.lua if both are enabled and found.
To open the folder holding those files in your system file manager instead, use Vim Motions: Open configuration directory in system explorer. The configuration file itself is selected inside the folder. Both commands work whether your configuration lives inside the vault or outside it.
Known issues
nmap L $and similar mappings may not apply if the vimrc file encounters I/O timing issues — reload the plugin as a workaround
See known-limitations > Vimrc for detailed technical limitations.