# zsh-vi-mode: a vi mode for Zsh that behaves like Vim

> The default Zsh vi mode is thin, and zsh-vi-mode replaces it with text objects, surrounds, system clipboard integration and a cursor that changes with the mode. Here is what it does, how to install it, and where it still falls short.

**jeffreytse/zsh-vi-mode** — 💻 A better and friendly vi(vim) mode plugin for ZSH.

- Repository: https://github.com/jeffreytse/zsh-vi-mode
- Stars: 4,458 · Forks: 154
- Language: Shell
- License: MIT
- Published: 2026-09-23 · Updated: 2026-09-23 · Language: en
- Canonical page: https://hysenlabs.com/projects/jeffreytse-zsh-vi-mode

## What zsh-vi-mode replaces, and who it is for

Zsh ships a vi mode you can turn on with `bindkey -v`, and the project's own README is blunt about how that goes. It describes users who enable the default mode, find that "some features were not perfect or non-existent, and some behaviors even were different from the native Vi(Vim) mode", and eventually give up on it. zsh-vi-mode exists to close that gap. It is written as pure Zsh with no third-party dependencies, and the feature list is essentially a list of Vim behaviours the stock mode lacks: text objects such as a word or inner word, surrounds that can be added, replaced, deleted or moved around, keyword switching for numbers, booleans, weekdays and months, undo and redo, cut, copy, paste and delete, and repeatable commands such as `10p` and `4fa`.

The intended user is someone who already edits in Vim and wants the same muscle memory at the shell prompt. That is a narrower audience than "everyone who uses Zsh". If you type `bindkey -v` once a year and forget about it, the plugin's surface area is larger than the problem you have. If your hands reach for `ciw` or `di"` while editing a long pipeline, the gap the README describes is real and this is aimed squarely at it.

## How the plugin works inside Zsh

The repository is small: at the top level there is `zsh-vi-mode.plugin.zsh`, `zsh-vi-mode.zsh`, a `LICENSE` file and a `.github/` directory. The plugin file is the entry point that a plugin manager sources, and the bulk of the behaviour lives in the second file. There is no daemon, no compiled binary and no network component, which is why the README can claim it works without third-party dependencies: everything runs as Zsh key bindings and widget functions loaded into your interactive shell.

That architecture has consequences worth naming. Because the plugin operates by rebinding keys in the current shell session, it interacts with anything else that binds keys, including your own `bindkey` calls and other plugins. The README's installation instructions for each manager reflect this. The zinit section, for example, says the use of `depth=1` ice is optional and that other types of ice are "neither recommended nor officially supported by this plugin", which is an unusually direct statement about a supported configuration boundary. The Oh My Zsh instructions add that plugins need to be added before `oh-my-zsh.sh` is sourced. Load order is not a detail here; it is part of how the plugin takes effect.

## Installing zsh-vi-mode and trying it for the first time

The requirement is ZSH 5.1.0 or newer. Installation depends on what you already use. With Antigen, the README bundles it in `.zshrc` with a single line:

```shell
antigen bundle jeffreytse/zsh-vi-mode
```

zplug, zgen, zinit, Antibody, Zap and Zim each get their own one-line form in the README, so pick the manager you already run rather than adding a second one. If you prefer a package manager, Homebrew installs it and then you source the plugin file from the Homebrew prefix:

```shell
brew install zsh-vi-mode
source $(brew --prefix)/opt/zsh-vi-mode/share/zsh-vi-mode/zsh-vi-mode.plugin.zsh
```

On Arch Linux the README gives `yay -S zsh-vi-mode` (or `yay -S zsh-vi-mode-git` for the unstable build), followed by sourcing `/usr/share/zsh/plugins/zsh-vi-mode/zsh-vi-mode.plugin.zsh`. Nix users source `${pkgs.zsh-vi-mode}/share/zsh-vi-mode/zsh-vi-mode.plugin.zsh` from `interactiveShellInit` or `initExtra`. After a fresh shell, the visible change is the cursor: the README lists "mode indication with different cursor styles" as a feature, so the shape of the cursor is your first signal that normal mode is active. From there, `vv` opens the current command line in an external editor, and `gx` opens the URL or file path under the cursor. Those two are the quickest way to confirm the plugin is loaded and responding.

## Where zsh-vi-mode gets in the way

The honest limitation is the one implied by the architecture: this is a keybinding layer, and keybinding layers collide. The README does not document a rollback procedure, and it does not publish a list of keys the plugin reserves versus keys it leaves alone. If you have a `.zshrc` full of your own `bindkey` lines, you should expect to test them after loading the plugin rather than assume they still fire. The zinit note about unsupported ice types is the closest the documentation comes to acknowledging that some loading configurations are outside what the author will help with.

Clipboard integration is the other soft spot. "System clipboard integration (Copy/Paste)" is listed as a feature, but the README does not describe what happens on a terminal or a remote session where no system clipboard is reachable. If you work mostly over SSH into machines without a clipboard provider, that part of the feature list is the part least likely to behave as it does on your laptop. And if you are not a vi user, none of this is a limitation you should work around; it is simply the wrong tool, because the plugin's value is entirely in motions you already know.

## zsh-vi-mode against the stock Zsh vi mode

The real alternative is not another plugin, it is `bindkey -v` and whatever you build on top of it yourself. The difference in approach is scope. The stock mode gives you normal and insert modes and a small set of movements; anything beyond that, you write as widget functions and bindings in your own configuration. That keeps your `.zshrc` under your control and adds no dependency, but it also means you reimplement text objects, surrounds and counts, or live without them.

zsh-vi-mode takes the opposite position: it ships that behaviour as a package and asks you to accept its bindings. The trade is convenience for control. If your existing setup is a handful of custom bindings you understand line by line, porting them into the plugin's model may cost more than it saves. If your setup is the default mode plus frustration, the plugin is the shorter path. Note also that the README's installation list includes Bash and Fish users only indirectly: the Homebrew and AUR instructions say to source the plugin in `.zshrc` "(or `.bashrc`)", but the plugin is written for Zsh, and the README does not explain what sourcing it under Bash actually does.

## Maintenance, licence and what an upgrade costs you

The repository is not archived, and the last push was on 2026-07-19. Releases are infrequent rather than steady: v0.12.0 landed on 2025-09-16, v0.11.0 on 2023-11-06, and v0.10.0 on 2023-07-17. That cadence matters for how you pin it. If you install through a plugin manager that tracks the default branch, you are following `master` between releases, and the gap between v0.11.0 and v0.12.0 shows that the branch can move for a long time without a tagged release. Pinning to a tag is the more predictable option; the README does not describe a versioning policy or a support window for older releases.

The licence is MIT, which is permissive and places few obligations on how you use or redistribute the plugin. That is a statement about the licence text, not legal advice; if you vendor the plugin into something you ship, read the `LICENSE` file yourself. Upgrade cost is low in the ordinary case, since there is no build step and no dependency tree to reconcile. The cost that does exist is re-testing your own key bindings after an update, because that is the surface the plugin changes.

## Conclusion

Adopt zsh-vi-mode if you already think in vi motions and want them at the prompt: text objects, surrounds, `10p` counts and `vv` for an external editor are the parts the default Zsh vi mode does not give you. Skip it if you only want to press Escape occasionally, or if you are not prepared to read the configuration section, since the plugin rebinds keys inside Zsh and the README does not promise that every existing binding survives. Before committing, check that your ZSH is at least 5.1.0, confirm which plugin manager you already run so you do not end up sourcing the plugin twice, and test `gx` and the clipboard keys on your own terminal, because the README does not document a fallback when the system clipboard is unavailable.

## FAQ

### How do I use zsh vi mode in Zsh?

Install zsh-vi-mode through one of the supported managers or package managers, then start a new shell. The cursor style changes to indicate the mode, and normal-mode motions, text objects, surrounds and commands such as `10p` become available. The README also documents `vv` to edit the command line in an external editor and `gx` to open the URL or path under the cursor.

### How do I install zsh vi mode?

The README gives one-line installs for Antigen, zplug, zgen, zinit, Antibody, Zap and Zim, plus `brew install zsh-vi-mode` on Homebrew and `yay -S zsh-vi-mode` on Arch. Homebrew and AUR users then source the plugin file from the install prefix in their `.zshrc`. ZSH 5.1.0 or newer is required.

### What is zsh vi mode?

zsh-vi-mode is a Zsh plugin that replaces the shell's default vi mode with behaviour closer to native Vim, written as pure Zsh with no third-party dependencies. Its feature list includes text objects, surrounds, keyword switching, undo and redo, repeatable commands and system clipboard integration.

## Sources

- [Issues](https://github.com/jeffreytse/zsh-vi-mode/issues)
- [jeffreytse/zsh-vi-mode on GitHub](https://github.com/jeffreytse/zsh-vi-mode)
- [License: MIT](https://github.com/jeffreytse/zsh-vi-mode/blob/master/LICENSE)
- [README](https://github.com/jeffreytse/zsh-vi-mode/blob/master/README.md)
- [Releases](https://github.com/jeffreytse/zsh-vi-mode/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/jeffreytse-zsh-vi-mode
