Skip to content

Templates

Rubin Bhandari edited this page Sep 23, 2026 · 2 revisions

Templates

An apply entry names a template. Built-ins:

Name bash zsh
source source each file source each file
PATH export PATH="<dir>:$PATH" same
path not available path=( "<dir>" $path )
fpath not available fpath=( "<dir>" $fpath )
defer degrades to source queue each source, drain when zle first goes idle
zcompile degrades to source guarded zcompile then source

defer and zcompile exist for zsh only, and under bash they render as plain source lines on purpose. One config stays valid in both shells.

defer schedules each file for after the first prompt draws, so a slow plugin stops delaying your prompt. Shelf embeds the scheduler, guarded against redefinition, and only emits it when some plugin uses defer. Non-interactive zsh never draws a prompt, so there the queue never drains and deferred plugins stay unloaded.

zcompile writes a .zwc bytecode file on first load and recompiles whenever the source is newer. zsh then auto-loads the fresh bytecode.

Custom templates live in [templates] and are referenced from apply by name:

[templates]
announce = "echo \"loading {{ name }}\"\n{% for file in files %}source \"{{ file }}\"\n{% endfor %}"

[plugins.demo]
github = "user/repo"
apply = ["announce"]

A name in apply that no template defines fails rendering with error: unknown template: <name>.

Template syntax

{{ value }}                  expression
{{ value | nl }}             filter, nl appends a newline
{% if x %} {% else if y %} {% else %} {% endif %}
{% for file in files %}      loop, exposes loop.index, loop.first, loop.last
{% for name, value in hooks %}   two variables for maps
{{ hooks?.pre }}             optional lookup, empty instead of an error

Available values per plugin:

Value Content
name Plugin name.
dir Installed directory.
file The single selected file, when file is set.
files List of selected files. files.0 indexes it.
hooks The hooks table.

A plain lookup on a missing key fails the render, which catches typos. Write hooks?.pre when absence is normal.

Without {{ }} or {% %} blocks, bare {name}, {dir}, {file}, and {nl} still expand. {file} in a block-free template repeats the whole template once per file.

Functions and filters

Form Arguments Result
nl(value) or value | nl one Adds a newline when one is missing. This is the only filter.
get(map, "key") two The value at key, empty when the key is missing. Never fails the render.

Anything else fails the render with unknown template function "x" or unknown template filter "x". Wrong argument counts report nl takes one argument or get takes two arguments.

Expressions also see string, number, and boolean literals ("text", 42, true, false), the not operator, and dotted paths such as files.0 and hooks.pre. A lookup that misses fails with unknown template value "x" or template value "x" has no field "y", unless it is written ?., which yields empty instead. Empty is false in {% if %}, which is what makes {{ hooks?.pre }} guards work.

Clone this wiki locally