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:

  1. vimrc
  2. .vimrc
  3. init.vim
  4. .init.vim
  5. obsidian.vimrc
  6. obsidian.vim
  7. .obsidian.vimrc
  8. .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

CommandDescription
map / nmap / imap / vmapMode-specific key mappings
noremap / nnoremap / inoremap / vnoremapNon-recursive mappings
unmap / nunmap / iunmap / vunmapRemove mappings
setSet plugin options (see tables below)
let mapleaderSet the leader key
exmapDefine a named command from an Obsidian command
obcommandExecute an Obsidian command by ID (alias of :ob)
sourceSource another vimrc file
gmap / gnoremapGlobal key mapping for non-editor contexts
gunmapRemove a global mapping
whichkeygroupName a which-key group by prefix
whichkeylabelLabel an individual binding in which-key
gwhichkeygroupName a global which-key group by prefix
gwhichkeylabelLabel a global binding in which-key
surroundmapRegister a surround pair, or override a built-in
surroundunmapRemove 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.

OptionAliasDescriptionDefault
textobjectstoMarkdown-aware text objectson
replacewithregisterrwrReplace-with-register operatoron
navigationnavHeading, list, and link navigationon
hardwraphwgq/gw hard-wrap operatorson
listcontinuationlcSmart list continuation on o/Oon
tablenavtnTable cell navigationon
workspacenavwnPane/tab/sidebar controlon
numbernuShow absolute line numbersoff
relativenumberrnuShow relative line numbersoff
flash—Flash-style f/F/t/T labelson
flashmultilinefmlFlash searches beyond current lineon
flashjump—Flash bidirectional jump mode (s)off
flashcleverf—Clever-f repetitionoff
flashsearch—Labels on /? search matcheson
labelmatchfontsizelmfsScale labels to match line font sizeoff
easymotionemEasyMotion/Hop navigationon
easymotiondimmingemdDim non-target text during EasyMotionon
hintmodehmVimium-style hint labelson
statusbarsbVim mode in status baron
chorddisplaycdPending keystrokes in status baron
powerlineplColored powerline status baroff
expandtabetUse spaces instead of tabson
pcre—Use JavaScript regexps in search/subston
cursorlineculCursor line highlighton
foldcolumnfdcFold column indicatorsoff
markgutter—Alias for signcolumn (compat)on
snippets—Enable snippet expansionon
snippetbundled—Include bundled Obsidian snippetson
vimtextareasvtaVim keybindings in text areasoff
yankring—Yank-ring paste cyclingon
harpoon—Harpoon file pinningon
dial—Enhanced increment/decrementoff
jumplist—Vim-style jump list for <C-o>/<C-i>on
foldawarenavigation—Master toggle for fold-aware navigationon
foldpersistence—Persist fold state across sessionsoff
undotreeutEnable undo tree trackingon
undofileudfPersist undo tree across sessionsoff
smoothcursorscEnable animated cursoroff
smoothcursorglidescgSmooth cursor movement (glide)on
smoothcursorsmearscmEnable smear trailon
subword—Spider.nvim-style subword motionsoff
picker—Telescope-style pickeron
pickerleadermappings—Leader key picker shortcutson
pickeromnisearch—Omnisearch picker integrationoff
pickertasks—Obsidian Tasks picker integrationoff
pickerdataview—Dataview picker integrationoff
ripgrep—Use ripgrep binary for grepoff
oil—Oil file exploreroff
oilhiddenfiles—Show hidden files in Oiloff
undotreeautoopen—Auto-open undo tree on branchoff
imswitching—Input method auto-switchingoff
ignorecaseicCase-insensitive searchon
smartcasescsOverride ignorecase when query has uppercaseon
hlsearchhlsHighlight all search matcheson
incsearchisIncremental search while typingon
wrapscanwsSearch wraps around documenton
gdefaultgd:s defaults to global replaceoff
startoflinesolVertical motions go to first non-blankon
joinspacesjsJ inserts two spaces after .!?off
shiftroundsr>>/<< round to shiftwidth multipleoff

Number options

Use set <option>=<value>.

OptionAliasDescriptionDefaultRange
scrolloffsoLines to keep visible above/below cursor50-9999
scanlimitslMax lines to scan for text objects205-200
labelfontsizelfsFont size for EasyMotion/hint labels1410-20
tabstoptsTab display width41-8
shiftwidthswIndent width41-8
textwidthtwLine wrap width for gq/gw800-200
insertmodeescapetimeoutimetTimeout (ms) for insert escape sequence1000100-5000
operatorshadowtimeoutost, timeoutlen, tmTimeout (ms) for operator-prefix and mapping-prefix disambiguation (equivalent to Neovim’s timeoutlen)10000-5000
numberwidthnuwMinimum line number column width21-20
jumplistsize—Maximum jump list entries2001-1000
undotreemaxnodesutmnMaximum undo tree nodes per file1000100-5000
yankhighlightduration—Yank highlight duration (ms)2000-5000
smoothcursorsmoothnessscsCursor movement smoothness0.50-1
smoothcursorstiffnessscstSmear trail head stiffness0.60.1-1
smoothcursortrailstiffnesssctsSmear trail tail stiffness0.30.1-1
smoothcursordampingscdSmear trail velocity decay0.850.1-0.99
smoothcursormaxlengthscmlMaximum smear trail length (px)40050-800
oilconfirmdeletethreshold—Oil delete confirmation threshold10-100

String options

Use set <option>=<value>.

OptionAliasDescriptionDefault
clipboardclipSystem clipboard sync (unnamed/unnamedplus)(off)
foldopenfdoMotion categories that auto-unfold (Neovim-compatible)block,hor,mark,percent,search,undo
insertmodeescapeimeTwo-key sequence to exit insert mode(off)
flashjumpkey—Key to trigger flash jump modes
flashminpatternlengthfmplMinimum chars before labels in jump mode1
yankhighlightmode—Yank highlight style (off/solid/fade)solid
easymotionlabelsemlCharacters for EasyMotion and flash labelsasdghklqwertyuiopzxcvbnmfj
hintlabelshlCharacters for hint mode labelsasdfghjkl
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 experimentalnative
whichkeywkWhich-key hints (off/leader/all)off
whichkeygroupingwkgWhich-key grouping (flat/grouped)grouped
whichkeysortwksWhich-key sort order (which-key/groups-first)which-key
whichkeyiconswkiWhich-key icons (on/off)on
workspacenavviewtypeswnvtView types for workspace nav interception(empty — uses defaults: markdown, graph, pdf, canvas, empty, image, bases)
cursorlineoptculoptCursor line highlight mode (number/line/screenline/both/screenline,number; comma lists accepted)both
signcolumnsclSign column visibility (auto[:N]/yes[:N]/no)auto
linenumbermodelnmLine number display (deprecated — use statuscolumn)hybrid
statuscolumnstcCustom 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)
whichwrapwwKeys that wrap to next/prev line at boundaries (h,l,b,s,<,>)b,s
virtualeditveCursor past EOL (onemore/all/block/insert)(off)
nrformatsnfNumber 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 definition

Group 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> ll

Only 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 H

The 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 bindings

Global 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 explorer

These 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

SettingReason
configModeCircular dependency — cannot control config file loading from vimrc
leaderBindingsAlready achievable via nmap <leader>x :command in vimrc
pickerKeymapComplex 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.