Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ a lot easier than figuring out mise's rules.
Notes:

- Paths which start with `mise` can be dotfiles, e.g.: `.mise.toml` or `.mise/config.toml`.
- This list doesn't include [Configuration Environments](/configuration/environments) which allow for environment-specific config files like `mise.development.toml`—set with `MISE_ENV=development`.
- This list doesn't include [Configuration Environments](/configuration/environments) which allow for environment-specific config files like `mise.development.toml`—set with `MISE_ENV=development`. Platform-specific environments like `mise.windows.toml` or `mise.macos-arm64.toml` can be enabled automatically with the [`auto_env` setting](/configuration/environments.html#platform-environments).
- See [`LOCAL_CONFIG_FILENAMES` in `src/config/mod.rs`](https://github.com/jdx/mise/blob/main/src/config/mod.rs) for the actual code for these paths and their precedence. Some legacy paths are not listed here for brevity.

## Configuration Hierarchy
Expand Down
42 changes: 42 additions & 0 deletions docs/configuration/environments.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,3 +76,45 @@ The rules around which file is written are different because we ultimately need
the docs for [`mise use`](/cli/use.html) for more information.

Multiple environments can be specified, e.g. `MISE_ENV=ci,test` with the last one taking precedence.

## Platform environments

With the [`auto_env` setting](/configuration/settings.html#auto_env) enabled, mise automatically
treats the following as active config environments, based on the current platform:

| Environment | Values |
| ------------- | ---------------------------------------------- |
| `{os_family}` | `unix` (not defined on Windows—use `windows`) |
| `{os}` | `linux`, `macos`, `windows` |
| `{os}-{arch}` | e.g. `linux-x64`, `macos-arm64`, `windows-x64` |

Architectures use mise's remapped names: `x86_64` → `x64` and `aarch64` → `arm64`.

This makes config files like `mise.windows.toml`, `mise.macos-arm64.toml`, or `mise.unix.toml`
load automatically, and matching lockfiles like `mise.windows.lock` get selected. All of the
usual config file locations and `.local.toml` variants work.

Platform environments have lower precedence than explicit `MISE_ENV` entries. The full order is
(later overrides earlier): `unix` < `{os}` < `{os}-{arch}` < explicit `MISE_ENV` entries.

Platform environments only affect config file discovery and lockfile selection. They are not
added to `MISE_ENV` itself: the `{{ mise_env }}` template variable and the `MISE_ENV` variable
passed to subprocesses and tasks only reflect explicit environments.

### Rollout

`auto_env` is currently **disabled by default**. Starting with mise `2027.6.0` it will default
to enabled; from `2026.12.0` until then, mise warns if it finds a platform-specific config file
that would be newly loaded. To control the behavior explicitly:

```toml
# .miserc.toml
auto_env = true # adopt the new behavior now
# or
auto_env = false # keep the old behavior and silence the warning
```

or set `MISE_AUTO_ENV=true` / `MISE_AUTO_ENV=false`. Like `MISE_ENV`, this is an early-init
setting: it must be set in `.miserc.toml` or via the environment variable — setting it in
`mise.toml` has no effect because config file discovery has already happened by the time
`mise.toml` is read.
71 changes: 71 additions & 0 deletions e2e/config/test_config_auto_env
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
#!/usr/bin/env bash

# Test auto_env: platform environments (unix, {os}, {os}-{arch}) are
# automatically active for config file discovery when enabled

os="$(uname -s)"
case "$os" in
Darwin) os=macos ;;
Linux) os=linux ;;
esac
arch="$(uname -m)"
case "$arch" in
x86_64) arch=x64 ;;
aarch64 | arm64) arch=arm64 ;;
esac

echo 'env.AAA = "base"
env.BBB = "base"' >mise.toml
echo 'env.AAA = "unix"
env.UNIX_LOADED = "1"' >mise.unix.toml
echo "env.AAA = \"$os\"" >"mise.$os.toml"
echo "env.AAA = \"$os-$arch\"" >"mise.$os-$arch.toml"
echo 'env.AAA = "prod"' >mise.prod.toml

# default: off, platform configs are not loaded
assert "mise env --json | jq -r .AAA" "base"

# the rollout warning never fires once the user has set auto_env explicitly,
# regardless of the phase the current version is in (the version-gated unset
# case is covered by the should_warn_auto_env unit tests)
assert_not_contains "MISE_AUTO_ENV=false mise env 2>&1" "load automatically"
assert_not_contains "MISE_AUTO_ENV=true mise env 2>&1" "load automatically"

# opt in: all platform configs load, most specific wins (unix < os < os-arch)
MISE_AUTO_ENV=true assert "mise env --json | jq -r .AAA" "$os-$arch"
MISE_AUTO_ENV=true assert "mise env --json | jq -r .UNIX_LOADED" "1"
Comment thread
greptile-apps[bot] marked this conversation as resolved.
MISE_AUTO_ENV=true assert "mise env --json | jq -r .BBB" "base"

# explicit MISE_ENV entries take precedence over auto platform envs
MISE_AUTO_ENV=true MISE_ENV=prod assert "mise env --json | jq -r .AAA" "prod"

# explicit MISE_ENV listing a platform env dedupes (file loaded once) and
# keeps its user-specified (higher) precedence
MISE_AUTO_ENV=true MISE_ENV=$os assert "mise env --json | jq -r .AAA" "$os"
MISE_AUTO_ENV=true MISE_ENV=$os assert "mise config ls | grep -c \"mise.$os.toml\"" "1"

# explicit opt-out
MISE_AUTO_ENV=false assert "mise env --json | jq -r .AAA" "base"

# auto envs are not added to MISE_ENV itself: {{ mise_env }} and MISE_ENV
# propagation to subprocesses only reflect explicit environments
cat <<'EOF' >>mise.toml
[tasks.print]
run = '{% if mise_env %}echo {{mise_env}}{% endif %}'
EOF
MISE_AUTO_ENV=true assert "mise run print" ""
MISE_AUTO_ENV=true MISE_ENV=prod assert "mise run print" "[prod]"

# auto_env can be enabled via .miserc.toml
echo 'auto_env = true' >.miserc.toml
assert "mise env --json | jq -r .AAA" "$os-$arch"
# env var overrides .miserc.toml
MISE_AUTO_ENV=false assert "mise env --json | jq -r .AAA" "base"
rm -f .miserc.toml

# global config dir platform configs load too
mkdir -p "$MISE_CONFIG_DIR"
echo "env.GLOBAL_AUTO = \"$os\"" >"$MISE_CONFIG_DIR/config.$os.toml"
MISE_AUTO_ENV=true assert "mise env --json | jq -r .GLOBAL_AUTO" "$os"
assert "mise env --json | jq -r .GLOBAL_AUTO" "null"
rm -f "$MISE_CONFIG_DIR/config.$os.toml"
40 changes: 40 additions & 0 deletions e2e/lockfile/test_lockfile_auto_env
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#!/usr/bin/env bash

# Test that auto platform environments (auto_env) select matching
# mise.<env>.lock lockfiles, and explicit MISE_ENV lockfiles still win

export MISE_LOCKFILE=1

os="$(uname -s)"
case "$os" in
Darwin) os=macos ;;
Linux) os=linux ;;
esac

cat >"mise.$os.toml" <<'EOF'
[tools]
tiny = "2"
EOF

touch "mise.$os.lock"

assert "mise install tiny@2.1.0"

# with auto_env enabled, mise.$os.toml is active and its lockfile is written
assert "MISE_AUTO_ENV=true mise use tiny@2"
assert_contains "cat mise.$os.lock" '[[tools.tiny]]'
assert_contains "cat mise.$os.lock" 'version = "2.1.0"'

# the locked version is honored when resolving with auto_env enabled
assert "MISE_AUTO_ENV=true mise ls tiny --json | jq -r '.[0].version'" "2.1.0"

# explicit env lockfile takes precedence over the auto platform one
cat >mise.prod.toml <<'EOF'
[tools]
tiny = "1"
EOF
touch mise.prod.lock
assert "mise install tiny@1.0.1"
assert "MISE_ENV=prod mise use tiny@1"
assert_contains "cat mise.prod.lock" 'version = "1.0.1"'
assert "MISE_AUTO_ENV=true MISE_ENV=prod mise ls tiny --json | jq -r '.[0].version'" "1.0.1"
4 changes: 4 additions & 0 deletions schema/mise.json
Original file line number Diff line number Diff line change
Expand Up @@ -538,6 +538,10 @@
"type": "boolean",
"deprecated": true
},
"auto_env": {
"description": "Automatically enable platform config environments (unix, {os}, {os}-{arch}).",
"type": "boolean"
},
"auto_install": {
"default": true,
"description": "Automatically install missing tools when running `mise x`, `mise run`, or as part of the 'not found' handler.",
Expand Down
4 changes: 4 additions & 0 deletions schema/miserc.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

30 changes: 30 additions & 0 deletions settings.toml
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,36 @@ env = "MISE_ASDF_COMPAT"
hide = true
type = "Bool"

[auto_env]
description = "Automatically enable platform config environments (unix, {os}, {os}-{arch})."
docs = """
When enabled, mise treats the following as active config environments (in addition
to any explicit `MISE_ENV`): `unix` (on unix-family platforms), the OS name
(`linux`/`macos`/`windows`), and `{os}-{arch}` (e.g. `macos-arm64`, `windows-x64`,
using mise's remapped arch names: `x86_64` -> `x64`, `aarch64` -> `arm64`).

This causes config files such as `mise.windows.toml`, `mise/config.macos-arm64.toml`,
or `mise.unix.toml` to be loaded automatically, and matching `mise.<env>.lock`
lockfiles to be selected. Platform environments have lower precedence than explicit
`MISE_ENV` entries; the full precedence order is `unix` < `{os}` < `{os}-{arch}` <
explicit `MISE_ENV` entries. Platform environments do not affect the
`{{ mise_env }}` template variable or the `MISE_ENV` variable passed to subprocesses.

When unset, this currently defaults to `false`. Starting with mise 2027.6.0 it will
default to `true`; set it to `false` to keep the old behavior, or `true` to adopt
the new behavior early.

This is an early-init setting: it must be set in `.miserc.toml` or via the
`MISE_AUTO_ENV` environment variable. Setting it in `mise.toml` will have no effect
because config file discovery has already occurred by the time `mise.toml` is read.

See [Configuration Environments](/configuration/environments.html) for more details.
"""
env = "MISE_AUTO_ENV"
optional = true
rc = true
type = "Bool"

[auto_install]
default = true
description = "Automatically install missing tools when running `mise x`, `mise run`, or as part of the 'not found' handler."
Expand Down
8 changes: 8 additions & 0 deletions src/config/miserc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,11 @@ pub fn get_env() -> Option<&'static Vec<String>> {
get().env.as_ref()
}

/// Get the auto_env value from miserc, if set.
pub fn get_auto_env() -> Option<bool> {
get().auto_env
}

/// Get the ceiling_paths value from miserc, if set.
pub fn get_ceiling_paths() -> Option<&'static BTreeSet<PathBuf>> {
get().ceiling_paths.as_ref()
Expand Down Expand Up @@ -148,6 +153,9 @@ fn merge_settings(target: &mut MisercSettings, source: MisercSettings) {
if source.env.is_some() {
target.env = source.env;
}
if source.auto_env.is_some() {
target.auto_env = source.auto_env;
}
if source.ceiling_paths.is_some() {
target.ceiling_paths = source.ceiling_paths;
}
Expand Down
Loading
Loading