docs/templates.md
Templates in mise provide a powerful way to configure different aspects of your environment and project settings.
A template is a string that contains variables, expressions, and control structures.
When rendered, the template engine (tera) replaces the variables with their values.
You can define and use templates in the following locations:
mise.toml configuration values
mise.toml file itself is not templated and must be valid toml.tool-versions files.miserc.toml files (limited context — see Template Support in .miserc.toml)Here is an example of a mise.toml file that uses templates:
[env]
PROJECT_NAME = "{{ cwd | basename }}"
TERRAFORM_VERSION = "1.0.0"
[tools]
# refers to env variable defined in this file
terraform = "{{ env.TERRAFORM_VERSION }}"
# refers to external env variable
node = "{{ get_env(name='NODE_VERSION', default='20') }}"
You will find more examples in the cookbook.
Mise uses tera to provide the template feature. In the template, there are 3 kinds of delimiters:
{{</span> and <span v-pre>}}</span> for expressions{%</span> and <span v-pre>%}</span> for statements{#</span> and <span v-pre>#}</span> for commentsAdditionally, use raw block to skip rendering tera delimiters:
{% raw %}
Hello {{ name }}
{% endraw %}
This will become <span v-pre>Hello {{name}}</span>.
Tera supports literals, including:
true (or True) and false (or False)"", '' or <code>``</code>[ and ] (trailing comma allowed)You can render a variable by using the <span v-pre>{{ name }}</span>.
For complex attributes, use:
., e.g. <span v-pre>{{ product.name }}</span>[], e.g. <span v-pre>{{ product["name"] }}</span>Tera also supports powerful expressions:
+-/*%==!=>=<=<>andornot~, e.g. <code v-pre>{{ "hello " ~ 'world' ~ `!` }}</code>{{ some_var in [1, 2, 3] }}</span>Tera also supports control structures such as <span v-pre>if</span> and
<span v-pre>for</span>. Read more.
You can modify variables using filters.
You can filter a variable by a pipe symbol (|) and may have named arguments
in parentheses. You can also chain multiple filters.
e.g. <span v-pre>{{ "Doctor Who" | lower | replace(from="doctor", to="Dr.") }}</span>
will output Dr. who.
Functions provide additional features to templates.
You can also uses tests to examine variables.
{% if my_number is not odd %}
Even
{% endif %}
Mise provides additional variables, functions, filters, and tests on top of tera features.
Mise exposes several variables. These variables offer key information about the current environment:
env: HashMap<String, String> – Accesses current environment variables as
a key-value map.cwd: PathBuf – Points to the current working directory.config_root: PathBuf – Locates the directory containing your mise.toml file, or in the case of something like ~/src/myproj/.config/mise.toml, it will point to ~/src/myproj.mise_bin: String - Points to the path to the current mise executablemise_pid: String - Points to the pid of the current mise processmise_env: Vec<String> - The configuration environment as specified by MISE_ENV, -E, or --env. Will be undefined if the configuration environment is not set.xdg_cache_home: PathBuf - Points to the directory of XDG cache homexdg_config_home: PathBuf - Points to the directory of XDG config homexdg_data_home: PathBuf - Points to the directory of XDG data homexdg_state_home: PathBuf - Points to the directory of XDG state hometools: HashMap<String, ToolInfo | ToolInfo[]> – Maps installed tool names to their info.
Available in task templates and env directives with tools = true.
tools.<name>.version: String – The resolved version (e.g., "22.1.0")tools.<name>.path: String – The install pathtools.<name>[0].version: String – The first versiontools.<name>[0].path: String – The first install pathtools.<name>[1].version: String – The second version, etc.In task run scripts, mise also exposes a usage map when the task has a usage
specification (see Task Arguments):
usage: HashMap<String, Value> – Parsed task arguments and flags, keyed by their
names. Values are not shell-escaped or quoted and may be:
The keys are the argument/flag names as written in the usage spec. If the name
contains -, use bracket access, e.g. <span v-pre>{{ usage["dry-run"] }}</span>.
Examples:
[tasks.deploy]
usage = '''
arg "<environment>" help="Target environment"
flag "-v --verbose" help="Enable verbose output"
arg "[tags]" var=#true
'''
run = '''
echo "env={{ usage.environment }}"
echo "verbose={{ usage.verbose }}"
echo "tag count={{ usage.tags | length }}"
{% for tag in usage.tags %}
echo "tag={{ tag }}"
{% endfor %}
'''
Tera offers many built-in functions.
[] indicates an optional function argument.
Some functions:
range(end, [start], [step_by]) - Returns an array of integers created
using the arguments given.
end: usize: stop before end, mandatorystart: usize: where to start from, defaults to 0step_by: usize: with what number do we increment, defaults to 1now([timestamp], [utc]) - Returns the local datetime as string or
the timestamp as integer.
timestamp: bool: whether to return the timestamp instead of the datetimeutc: bool: whether to return the UTC datetime instead of
the local one{{ now() | date(format="%Y") }}</span> gets the current year.throw(message) - Throws with the message.get_random(end, [start]) - Returns a random integer in a range.
end: usize: upper end of the rangestart: usize: defaults to 0get_env(name, [default]): Returns the environment variable value by name.
Prefer env variable than this function.
name: String: the name of the environment variabledefault: String: a default value in case the environment variable is not found.
Throws when can't find the environment variable and default is not set.Tera offers more functions. Read more on tera documentation.
Mise offers a slew of useful functions in addition to tera's built-ins.
These functions are available in all tasks, and will always behave the same way regardless of the task definition they are used in. In other words, their return values are consistent across task definition(s).
exec(command) -> String – Runs a shell command and returns its output as a string.arch() -> String – Retrieves the system architecture, such as x64 or arm64.os() -> String – Returns the name of the operating system,
e.g. linux, macos, windows.os_family() -> String – Returns the operating system family, e.g. unix, windows.num_cpus() -> usize – Gets the number of CPUs available on the system.choice(n, alphabet) - Generate a string of n with random sample with replacement
of alphabet. For example, choice(64, HEX) will generate a random
64-character lowercase hex string.read_file(path) -> String – Reads the contents of a file at the given path and returns
it as a string.These functions are task-specific and behave differently depending on the task they are used in. In other words, their return values may (but are not guaranteed to) be consistent across executions of any given task, and should be expected to be inconsistent across different task definition(s).
For example, task_source_files() returns a different set of filepaths depending on the sources of the task it's called from.
task_source_files() -> Vec<String></span> – Returns the task's sources
as an array of resolved file paths. This function processes glob patterns and Tera template strings
defined in the task's sources, expanding them into actual file paths. If a pattern doesn't match any
files, it will be omitted from the result. Returns an empty array if no sources are configured or if
no files match the patterns.# Using exec to get command output
[alias.node.versions]
current = "{{ exec(command='node --version') }}"
# Using read_file to include content from a file
[env]
VERSION = "{{ read_file(path='VERSION') | trim }}"
# Access resolved source files in task scripts
[tasks.example]
sources = ["src/**/*.ts", "package.json"]
run = '''
{% for file in task_source_files() %}
echo "Processing: {{ file }}"
{% endfor %}
'''
The exec function supports the following options:
command: String – [required] The command to run.cache_key: String – The cache key to store the result.
If the cache key is provided, the result will be cached and reused
for subsequent calls.cache_duration: String – The duration to cache the result.
The duration is in seconds, minutes, hours, days, or weeks.
e.g. cache_duration="1d" will cache the result for 1 day.Tera offers many built-in filters.
[] indicates an optional filter argument.
Some filters:
str | lower -> String – Converts a string to lowercase.str | upper -> String – Converts a string to uppercase.str | capitalize -> String – Converts a string with all its characters lowercased
apart from the first char which is uppercased.str | replace(from, to) -> String – Replaces a string with all instances of
from to to. e.g., <span v-pre>{{ name | replace(from="Robert", to="Bob")}}</span>str | title -> String – Capitalizes each word inside a sentence.
e.g., <span v-pre>{{ "foo bar" | title }}</span> becomes Foo Bar.str | trim -> String – Removes leading and trailing whitespace.str | trim_start -> String – Removes leading whitespace.str | trim_end -> String – Removes trailing whitespace.str | truncate -> String – Truncates a string to the indicated length.str | first -> String – Returns the first element in an array or string.str | last -> String – Returns the last element in an array or string.str | join(sep) -> String – Joins an array of strings with a separator,
such as <span v-pre>{{ ["a", "b", "c"] | join(sep=", ") }}</span>
to produce a, b, c.str | length -> usize – Returns the length of a string or array.str | reverse -> String – Reverses the order of characters in a string or
elements in an array.str | urlencode -> String – Encodes a string to be safely used in URLs,
converting special characters to percent-encoded values.arr | map(attribute) -> Array – Extracts an attribute from each object
in an array.arr | concat(with) -> Array – Appends values to an array.num | abs -> Number – Returns the absolute value of a number.num | filesizeformat -> String – Converts an integer into
a human-readable file size (e.g., 110 MB).str | date(format) -> String – Converts a timestamp to
a formatted date string using the provided format,
such as <span v-pre>{{ ts | date(format="%Y-%m-%d") }}</span>.
Find a list of time format on chrono documentation.str | split(pat) -> Array – Splits a string by the given pattern and
returns an array of substrings.str | default(value) -> String – Returns the default value
if the variable is not defined or is empty.Tera offers more filters. Read more on tera documentation.
str | hash([algorithm], [len]) -> String – Generates a hash for the input string.
algorithm: "sha256" | "blake3": hash algorithm to use (default: "sha256")len: usize: truncates the hash string to the given size{{ "foo" | hash }}</span> – SHA256 hash (default){{ "foo" | hash(algorithm="blake3") }}</span> – BLAKE3 hash{{ "foo" | hash(len=8) }}</span> – SHA256 hash truncated to 8 characterspath | hash_file([len]) -> String – Returns the BLAKE3 hash of the file
at the given path.
len: usize: truncates the hash string to the given sizepath | absolute -> String – Converts the input path into
an absolute path. Does not require the path to exist.path | canonicalize -> String – Converts the input path into
absolute input path version. Throws if path doesn't exist.path | basename -> String – Extracts the file name from a path,
e.g. /foo/bar/baz.txt becomes baz.txt.path | file_size -> String – Returns the size of a file in bytes.path | dirname -> String – Returns the directory path for a file,
e.g. /foo/bar/baz.txt becomes /foo/bar.path | basename -> String – Returns the base name of a file,
e.g. /foo/bar/baz.txt becomes baz.txt.path | extname -> String – Returns the extension of a file,
e.g. /foo/bar/baz.txt becomes .txt.path | file_stem -> String – Returns the file name without the extension,
e.g. /foo/bar/baz.txt becomes baz.path | file_size -> String – Returns the size of a file in bytes.path | last_modified -> String – Returns the last modified time of a file.path[] | join_path -> String – Joins an array of paths into a single path.For example, you can use split(), concat(), and join_path filters to
construct a file path:
[env]
PROJECT_CONFIG = "{{ [config_root] | concat(with='bar.txt') | join_path }}"
str | quote -> String – Quotes a string. Converts ' to \' and
then quotes str, e.g 'it\'s str'.str | kebabcase -> String – Converts a string to kebab-casestr | lowercamelcase -> String – Converts a string to lowerCamelCasestr | uppercamelcase -> String – Converts a string to UpperCamelCasestr | snakecase -> String – Converts a string to snake_casestr | shoutysnakecase -> String – Converts a string to SHOUTY_SNAKE_CASETera offers many built-in tests. Some tests:
defined - Returns true if the given variable is defined.string - Returns true if the given variable is a string.number - Returns true if the given variable is a number.starting_with - Returns true if the given variable is a string and starts with
the arg given.ending_with - Returns true if the given variable is a string and ends with
the arg given.containing - Returns true if the given variable contains the arg given.matching - Returns true if the given variable is a string and matches the regex
in the argument.Tera offers more tests. Read more on tera documentation.
Mise offers additional tests:
if path is dir – Checks if the provided path is a directory.if path is file – Checks if the path points to a file.if path is exists – Checks if the path exists..miserc.toml files support Tera templates, but with a limited context. This is because
.miserc.toml is loaded very early — before mise.toml, Settings, and the main config are
parsed — so only information available at OS level can be used.
env: HashMap<String, String> – OS environment variables (same as in mise.toml)config_root: PathBuf – Directory containing the .miserc.toml filecwd: PathBuf – Current working directoryxdg_cache_home, xdg_config_home, xdg_data_home, xdg_state_home – XDG base directoriesarch(), os(), os_family(), num_cpus(), choice(), etc.absolute, dirname, basename, hash, etc.mise_env – This is what .miserc.toml defines; it cannot reference itselfexec() – Requires Settings, which are not yet loadedread_file() – Not registered in the early-init context (needs per-file directory resolution that is not set up at this stage)mise_bin, mise_pid – Not meaningful at this stage# ~/.config/mise/miserc.toml
# Use $HOME to set a ceiling path (stops config search at home directory)
ceiling_paths = ["{{ env.HOME }}"]
# Ignore a config path relative to home
ignored_config_paths = ["{{ env.HOME }}/shared"]
Conditionals work too — {% if %} blocks at the top level produce empty lines when the
condition is false, which TOML ignores:
# ~/.config/mise/miserc.toml
{% if os() == "linux" %}
ceiling_paths = ["{{ env.HOME }}/work"]
{% endif %}
::: tip If a template fails to render (e.g. due to an undefined variable), mise will log a warning and fall back to the raw content. :::
::: warning
If your .miserc.toml values contain literal <span v-pre>{{</span>, {%, or {# characters
(not intended as templates), wrap them in a {% raw %}...{% endraw %} block to prevent Tera
from interpreting them.
:::