Environment variables
Set project environment variables under [env] in mise.toml. mise applies them to commands run with mise exec, to tasks, to shims, and to shells where mise is activated.
For separate files per deployment, such as mise.production.toml, see Config environments. For values that only templates need, use [vars]. To keep secret values out of plaintext config, see Secrets.
Set and unset variables
[env]
NODE_ENV = "production"Check the value in a child process without changing your shell:
mise exec -- sh -c 'echo "$NODE_ENV"'
# productionA value can be a string or an integer; true becomes the string "true". Set a variable to false to unset it, for example one that your shell or a parent directory's config sets:
[env]
NODE_ENV = falsemise set and mise unset edit [env] from the command line:
mise set NODE_ENV=development # writes NODE_ENV = "development" under [env]
mise set NODE_ENV # prints development
mise set # lists each variable, its value, and the file it comes from
mise unset NODE_ENV # removes itmise set writes to the nearest directory that has config. When that directory has both mise.toml and mise.local.toml, it writes mise.toml; see which file a write uses. Pass -E staging to write mise.staging.toml, -g to write the global config, and --prompt or --stdin to keep a value out of your shell history.
To print the resolved environment, including PATH entries and variables that tools set, run mise env. Add --json or --dotenv for other formats.
Where variables apply
| How you run a command | Receives [env] |
|---|---|
mise exec -- <command> | Yes |
mise run <task> | Yes, plus the task's own env |
| A shell where mise is activated | Yes, updated each time you change directories |
| A shim | Yes, for the program the shim runs |
mise en | Yes, in a new shell that does not update when you change directories |
Variables combine with tools in the same file:
mise use node@24
mise set MY_VAR=123
mise exec -- node -p process.env.MY_VAR
# 123Task-specific variables
A task's own env applies only to that task and accepts the same values and directives as [env]:
[tasks.print]
env = { MY_VAR = "my variable", _.file = ".env.print" }
run = "echo $MY_VAR"See task env.
Defaults and required variables
Defaults
default sets a fallback and keeps a value that is already there:
[env]
NODE_ENV = { default = "development" }mise keeps NODE_ENV when it is already set to a non-empty value, either in the environment mise started with or by a lower-precedence config file such as the global config. Otherwise it sets NODE_ENV to development. A default must be a string or an integer.
Required variables
required = true declares a variable that something else must set. mise checks that it is set but never assigns it. The check passes when the variable is in the environment mise started with, or when any other config file sets it, such as mise.local.toml, a parent directory's config or the global config:
[env]
DATABASE_URL = { required = true }[env]
DATABASE_URL = "postgres://localhost/app"Give required a string instead of true to show help text when the variable is missing:
[env]
DATABASE_URL = { required = "Set DATABASE_URL to your PostgreSQL connection string" }When a required variable is missing, mise exec, mise run, mise env and mise set stop with an error that includes the help text. An activated shell prints a warning instead and keeps going, so a missing value does not break your prompt:
mise WARN Required environment variable 'DATABASE_URL' is not defined. It must be set before mise runs or in a later config file. (Required in: ~/src/app/mise.toml)
Help: Set DATABASE_URL to your PostgreSQL connection stringrequired cannot be combined with value or default.
To mask a value in task output, including one a caller supplies for a required variable, mark it with redact = true; see Redaction and CI masking.
Reference other values
Values are Tera templates, and they also support shell-style $VAR expansion:
[env]
PROJECT_LIB = "{{config_root}}/lib"
LD_LIBRARY_PATH = "{{env.PROJECT_LIB}}:${LD_LIBRARY_PATH:-}"A value can use only variables defined above it in the same file, in a lower-precedence config file, or in the environment mise started with.
Templates
{{config_root}} is the project directory and {{env.NAME}} reads a variable. See Tera templates for the full context and filters.
Shell-style expansion
| Syntax | Result |
|---|---|
$VAR | The value of VAR |
${VAR} | The same; use it before letters or digits, as in ${VAR}_suffix |
${VAR:-default} | default when VAR is unset or empty |
${VAR:-} | An empty string when VAR is unset, without a warning |
Expansion runs after template rendering, so a value can mix both. A variable that is not defined and has no default stays as written, and mise prints a warning. Turn expansion off with env_shell_expand = false.
Use values that tools set
mise resolves [env] before it loads tools, so values can configure tool installation, for example CFLAGS for a source build. To use something a tool provides, such as its version or its PATH entries, add tools = true. mise then resolves that entry after tools load:
[env]
NODE_VERSION = { value = "{{ tools.node.version }}", tools = true }
_.path = { path = "{{env.GEM_HOME}}/bin", tools = true }tools = true works on variables, _.file, _.path, _.source and plugin directives. _.python.venv always resolves after tools and does not accept the option.
Precedence
When several config files set the same variable, the more specific file wins:
mise.local.tomlwins overmise.toml.- With
MISE_ENV=dev,mise.dev.tomlwins overmise.toml,mise.local.tomlwins overmise.dev.toml, andmise.dev.local.tomlwins over all three. - A project's config wins over a parent directory's config.
- Any project config wins over the global config (
~/.config/mise/config.toml).
See config files for the full list of locations.
mise evaluates config files from the lowest precedence to the highest, and the entries in each file in the order you write them, so each value can reference anything set before it. A value in [env] replaces a variable of the same name in the environment mise started with; default and required are the exceptions described above.
Env directives
Directives load variables from files and scripts and add PATH entries. They live in a table named _, because a variable cannot contain a nested table. _.file, _.path and _.source each take a path, a table with path and options, or an array of either:
[env]
_.file = ".env"
_.path = ["bin", "node_modules/.bin"]
_.source = { path = "scripts/env.sh", redact = true }Relative paths resolve against the project directory, even when the config file is in .config/mise/ or .mise/ (see config_root). Paths can use templates, $VAR and ~. Directives run in the order you write them, so _.path can use a variable that _.source set above it; _.python.venv always runs last.
| Option | _.file | _.source | _.path | Effect |
|---|---|---|---|---|
path | Yes | Yes | Yes | One path or a list of paths |
tools | Yes | Yes | Yes | Resolve after tools load (details) |
redact | Yes | Yes | No | Mark every loaded value as sensitive |
expand | Yes | No | No | Let the file use values loaded before it |
env._.file
Load variables from a file:
[env]
_.file = ".env"- The extension selects the format.
.json,.yamland.tomlfiles are parsed as structured files whose top-level keys become variables. Any other name, including.ymland.env, is parsed as dotenv. - The path can be a glob pattern such as
.env.*; every matching file is loaded. - A path that matches no file is skipped without an error, so
_.filecan point at an optional, untracked.env. - Values from the file replace variables already in the environment.
[env]
_.file = [
".env.json",
"~/.config/myapp/.env",
{ path = ".secrets.yaml", redact = true },
]Dotenv files use KEY=value lines, with # comments and quoted values. Quoting works as in a shell: single-quoted text is literal, and quoted and unquoted parts next to each other are joined with their quotes removed, so 'it'\''s' is it's. A quote with no partner later on its line, as in O'Brien, is kept as written. A partner in a trailing comment still counts, so write NAME="O'Brien" # owner's name. Single-quote a value that must keep its own quotes, such as JSON: CONFIG='{"debug": true}'. A dotenv value can reference variables assigned earlier in the same file, then variables from the environment mise started with. JSON, YAML and TOML values are read literally, so a $ stays a $. Set expand = true to let a file of any format reference values loaded before it, from earlier files or earlier [env] entries:
[env]
BASE = "/opt/project"
_.file = { path = ".env.json", expand = true }expand = true has no effect when env_shell_expand is false.
mise decrypts SOPS-encrypted JSON, YAML and TOML files as it loads them; see SOPS files.
To load a dotenv file from the current directory and every parent directory, set the env_file setting, for example MISE_ENV_FILE=.env. Unlike _.file, which resolves paths against the config file that declares it, env_file searches upward from the current directory, and a closer file wins.
env._.path
Add directories to PATH, ahead of the directories already in it:
[env]
_.path = [
"bin",
"{{config_root}}/node_modules/.bin",
"~/.local/share/mytool/bin",
]Use _.path for PATH. A PATH key in [env] is ignored by mise exec, mise env and activated shells.
env._.source
Run a bash script and take the variables it exports:
[env]
_.source = "scripts/env.sh"mise runs the script with bash, as if you ran source scripts/env.sh, and ignores its shebang. For another language, use a task or an environment plugin.
- Variables the script exports or changes are added, and variables it unsets are removed.
- The path can be a glob pattern, and a path that matches no file is skipped, as with
_.file. - The script runs each time mise computes the environment, so keep it fast and safe to run more than once.
- Safe mode never runs it, not even from the global config.
A script can prepend to PATH:
export PATH="/new/bin:$PATH"mise ignores other PATH changes, such as appending, removing or reordering entries, because it manages PATH entries itself so it can remove them cleanly when you leave the directory. Relative prepended entries resolve against the project directory, and empty entries are ignored.
On Windows, _.source needs a POSIX bash such as Git for Windows or MSYS2. mise finds it the same way it does for bash tasks, including common install locations that are not on PATH; set MISE_BASH_PATH to choose one. mise never uses the WSL launcher at C:\Windows\System32\bash.exe, because WSL cannot read Windows script paths. PATH entries the script prepends in /c/... or /cygdrive/c/... form are converted to Windows form.
env._.python.venv
Create and activate a Python virtual environment:
[env]
_.python.venv = { path = ".venv", create = true }See Automatic virtualenv activation for all options.
Directives from plugins
An environment plugin adds its own directive. Install the plugin, then name it under _ with the options the plugin documents:
[env]
_.my-env-plugin = { api_url = "https://api.example.com" }tools and redact also work on plugin directives. If the plugin is not installed and mise has no source to install it from, mise warns and skips the directive. To write an environment plugin, see Environment plugins.
Variables that configure mise
mise reads MISE_* variables such as MISE_DATA_DIR when it starts, before it loads [env], so setting one in [env] does not change how that mise process behaves. Set them in your shell or CI environment, or use [settings]. See MISE_* variables.
The SOPS key variables are the exception: mise reads MISE_SOPS_AGE_KEY and MISE_SOPS_AGE_KEY_FILE from [env] to decrypt encrypted files listed after them; see SOPS files.
Turn off config env
mise --no-env, MISE_NO_ENV=1 or the no_env setting skips [env] and env directives from every config file.
In safe mode (MISE_SAFE=1), mise ignores [env] and env directives from project config, and never runs _.source.
Next steps
- Secrets: encrypt values or fetch them from a secret manager, and mask them in output.
- Config environments: switch sets of values with
MISE_ENV. - Hooks: run commands when you enter or leave a project.
- Tera templates: the functions and filters values can use.
Deprecated syntax
| Deprecated | Use instead | Removed in |
|---|---|---|
env.mise.* | env._.* | 2026.12.0 |
value or values in a _.file, _.path or _.source table | path | 2026.12.0 |
Top-level env_file or dotenv | env._.file | 2027.4.0 |
Top-level env_path | env._.path | 2027.4.0 |
The value and values rule also applies to directives under vars._. It does not affect value in an ordinary variable table, such as SECRET = { value = "...", redact = true }, or the options of plugin directives.