Get the cure -

Antidote is a Zsh plugin manager made from the ground up thinking about performance.

It is fast because it can do things concurrently, and generates an ultra-fast static plugin file that you can easily load from your Zsh config.

It is written natively in Zsh, is well tested, and picks up where Antibody left off.

How much faster?

Loading your plugins with Antidote is fast! It was designed with speed in mind.

A lot of sites recommend benchmarking with this simple, but outdated, method:

for i in $(seq 10); do
  /usr/bin/time zsh -lic exit

You can use that, however, zsh-bench provides a much better way to benchmark Zsh startup times. Have a look at how Antidote compares to other setups here.

The antidote developer regularly publishes zsh-bench results in his dotfiles repo.


antigen logo antigen
antibody logo antibody
antidote logo antidote

The short version:

The original Antigen plugin manager was slow. Antibody was written to address this, but was written in Go, not Zsh. Other native Zsh plugin managers caught up on speed, so it was deprecated. But Antibody had some nice features that aren’t in other Zsh plugin managers. So Antidote was created to carry on as the next generation of antigen-like Zsh plugin managers.

See also:


Install with git

You can install the latest release of antidote by cloning it with git:

# first, run this from an interactive zsh terminal session:
git clone --depth=1 ${ZDOTDIR:-~}/.antidote

Install with a package manager

antidote may also be available in your system’s package manager:


After installation, the recommended way to use antidote is to call the antidote load command from your .zshrc:

# now, simply add these two lines in your ~/.zshrc

# source antidote
source ${ZDOTDIR:-~}/.antidote/antidote.zsh

# initialize plugins statically with ${ZDOTDIR:-~}/.zsh_plugins.txt
antidote load

Note: If you installed antidote with a package manager, the path will be different than ${ZDOTDIR:-~}/.antidote so you will need to modify the above script with source /path/to/antidote.zsh. For example, if you are using homebrew on macOS, the command you will need will be: source $(brew --prefix)/opt/antidote/share/antidote/antidote.zsh. Be sure to follow the instructions provided by your package manager.

Ultra high performance install

If you want to squeeze every last drop of performance out of your antidote config, you can do all the things antidote load does for you on your own. If you’re fairly comfortable with zsh, this is a more robust .zshrc snippet you can use:

# ~/.zshrc

# Set the name of the static .zsh plugins file antidote will generate.

# Ensure you have a .zsh_plugins.txt file where you can add plugins.
[[ -f ${zsh_plugins:r}.txt ]] || touch ${zsh_plugins:r}.txt

# Lazy-load antidote.
autoload -Uz $fpath[-1]/antidote

# Generate static file in a subshell when .zsh_plugins.txt is updated.
if [[ ! $zsh_plugins -nt ${zsh_plugins:r}.txt ]]; then
  (antidote bundle <${zsh_plugins:r}.txt >|$zsh_plugins)

# Source your static plugins file.
source $zsh_plugins

This method boils down to the bare essentials and will run antidote bundle only if absolutely necessary. However, note that you’ll really only be saving small fractions of a second over calling the much simpler antidote load command directly.


Antidote achieves its speed by doing all the work of cloning plugins up front and generating the code your .zshrc needs to source those plugins. Typically, we want to do this via a plugins file.

Plugins file

A plugins file is basically any text file that has one plugin per line.

In our examples, let’s assume we have a ~/.zsh_plugins.txt file with these contents:

# .zsh_plugins.txt

# comments are supported like this

# empty lines are skipped

# annotations are also allowed:
romkatv/zsh-bench kind:path
olets/zsh-abbr    kind:defer

# frameworks like oh-my-zsh are supported
ohmyzsh/ohmyzsh path:lib
ohmyzsh/ohmyzsh path:plugins/colored-man-pages
ohmyzsh/ohmyzsh path:plugins/magic-enter

# or lighter-weight ones like zsh-utils
belak/zsh-utils path:editor
belak/zsh-utils path:history
belak/zsh-utils path:prompt
belak/zsh-utils path:utility
belak/zsh-utils path:completion

# prompts:
#   with prompt plugins, remember to add this to your .zshrc:
#   `autoload -Uz promptinit && promptinit && prompt pure`
sindresorhus/pure     kind:fpath
romkatv/powerlevel10k kind:fpath

# popular fish-like plugins
zdharma-continuum/fast-syntax-highlighting kind:defer

Now that we have a plugins file, let’s look how can we load them!

Loading plugins

If you followed the recommended install procedure, your plugins will already be loaded when you called antidote load in your .zshrc.

However, you could choose generate your static plugins file manually with antidote bundle. Basically, antidote will only need to run when you change your .zsh_plugins.txt file. After you change this, use antidote to regenerate the static file.

Assuming the .zsh_plugins.txt be created above, we can run:

# generate ~/.zsh_plugins.zsh
antidote bundle <~/.zsh_plugins.txt >~/.zsh_plugins.zsh

We can run this at any time to update our static .zsh_plugins.zsh file, however if you followed the recommended install procedure you won’t need to do this yourself.

Finally, the static generated plugins file gets sourced in your .zshrc.

# .zshrc
source ~/.zsh_plugins.zsh

Note that to use antidote bundle this way, we will never want to call antidote init. Be sure that’s not in your ~/.zshrc. antidote init is a wrapper provided for backwards compatibility for users familiar with antibody and antigen, but is no longer recommended.

CleanMyMac or similar tools

If you use CleanMyMac or similar tools, make sure to set it up to ignore the antidote home folder, otherwise it may delete your plugins.

You may also change Antidote’s home folder, for example:

export ANTIDOTE_HOME=~/.cache/antidote


There are a few options you can use that should cover most common use cases. Let’s take a look!


The kind annotation can be used to determine how a bundle should be treated.


The default is kind:zsh, which will look for files that match these globs:

  • *.plugin.zsh
  • *.zsh
  • *.sh
  • *.zsh-theme

And source them.


$ antidote bundle zsh-users/zsh-autosuggestions kind:zsh
fpath+=( /Users/matt/Library/Caches/antidote/ )
source /Users/matt/Library/Caches/antidote/


The kind:path mode will just put the plugin folder in your $PATH.


$ antidote bundle romkatv/zsh-bench kind:path
export PATH="/Users/matt/Library/Caches/antidote/$PATH"


The kind:fpath only puts the plugin folder on the fpath, doing nothing else. It can be especially useful for completion scripts that aren’t intended to be sourced directly, or for prompts that support promptinit.


$ antidote bundle sindresorhus/pure kind:fpath
fpath+=( /Users/matt/Library/Caches/antidote/ )


The kind:clone only gets the plugin, doing nothing else. It can be useful for managing a package that isn’t directly used as a shell plugin.


$ antidote bundle mbadolato/iTerm2-Color-Schemes kind:clone


The kind:defer option defers loading of a plugin. This can be useful for plugins you don’t need available right away or are slow to load. Use with caution.


$ antidote bundle olets/zsh-abbr kind:defer
if ! (( $+functions[zsh-defer] )); then
  fpath+=( /Users/matt/Library/Caches/antidote/ )
  source /Users/matt/Library/Caches/antidote/
fpath+=( /Users/matt/Library/Caches/antidote/ )
zsh-defer source /Users/matt/Library/Caches/antidote/


You can also specify a branch to download, if you don’t want the main branch for whatever reason.


$ antidote bundle zsh-users/zsh-autosuggestions branch:develop
fpath+=( /Users/matt/Library/Caches/antidote/ )
source /Users/matt/Library/Caches/antidote/


You may specify a subfolder or a specific file if the repo you are bundling contains multiple plugins. This is especially useful for frameworks like Oh-My-Zsh.

File Example:

$ antidote bundle ohmyzsh/ohmyzsh path:lib/clipboard.zsh
source /Users/matt/Library/Caches/antidote/

Folder Example:

$ antidote bundle ohmyzsh/ohmyzsh path:plugins/magic-enter
fpath+=( /Users/matt/Library/Caches/antidote/ )
source /Users/matt/Library/Caches/antidote/

Friendly Names

You can also change how Antidote names the plugin directories by adding this to your .zshrc:

zstyle ':antidote:bundle' use-friendly-names 'yes'

Now, the directories where plugins are stored is nicer to read. For example: becomes zsh-users__zsh-autosuggestions.

$ antidote bundle zsh-users/zsh-autosuggestions
fpath+=( /Users/matt/Library/Caches/antidote/zsh-users__zsh-autosuggestions )
source /Users/matt/Library/Caches/antidote/zsh-users__zsh-autosuggestions/zsh-autosuggestions.plugin.zsh


Let’s look what other commands antidote has available for us!


You can see where antidote is keeping the plugins with the home command:

$ antidote home

Of course, you can remove the entire thing with:

rm -rf $(antidote home)

if you decide to start fresh or to use something else.

If you clear out your plugins, don’t forget to also run:

rm ~/.zsh_plugins.zsh


You can quickly add a plugin to your plugins file with antidote install:

$ antidote install zsh-users/zsh-autosuggestions
Bundle 'zsh-users/zsh-autosuggestions' added to '/Users/matt/.zsh_plugins.txt'.

If you have an alternate location for your plugins file, you can provide that too:

$ antidote install zsh-users/zsh-history-substring-search ${ZDOTDIR:-~}/myplugins.conf
Bundle 'zsh-users/zsh-history-substring-search' added to '/Users/matt/.zsh/myplugins.conf'.

Don’t forget to reload zsh afterwards to load the plugin you just added!


You can list the plugins you have cloned to your antidote home folder:

$ antidote list                 /Users/matt/Library/Caches/antidote/        /Users/matt/Library/Caches/antidote/
# ...


You can use antidote load in your .zshrc to clone and source everything in your plugins file, which by default is ${ZDOTDIR:-$HOME}/.zsh_plugins.txt:

# .zshrc
# make a static plugins file and source it to load all your plugins
antidote load

It also takes a parameter if you prefer to use a custom plugins file:

# .zshrc
antidote load ${ZDOTDIR:-~}/myplugins.conf


You can see the path being used for a cloned bundle.

$ antidote path ohmyzsh/ohmyzsh

This is particularly useful for projects like oh-my-zsh that rely on storing its path in the $ZSH environment variable:

$ ZSH=$(antidote path ohmyzsh/ohmyzsh)


You can remove a bundle completely by purging it:

$ antidote purge ohmyzsh/ohmyzsh
Removing ohmyzsh/ohmyzsh...

You can also remove all antidote bundles and the static cache file to start fresh:

$ rm -rf $(antidote home)
$ rm ${ZDOTDIR:-~}/.zsh_plugins.zsh


Antidote can update itself, and all bundles in a single pass.

Just run:

$ antidote update
Updating antidote...
Updating f6c4391..7b8d560
Updating all bundles in /Users/matt/Library/Caches/antidote...


Help getting started

If you want to see a full-featured example Zsh configuration using antidote, you can have a look at the zdotdir project. Feel free to incorporate code or plugins from it into your own dotfiles, or you can fork it to get started building your own Zsh config from scratch driven by antidote.


For information about enabling Zsh completion features when using antidote, see the completions section.

Migrating from another plugin manager

Migrating from antibody? see here. Migrating from antigen? see here.


Having trouble with antidote? see troubleshooting tips here.


Want to file a bug report? see GitHub issues here.