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
46 changes: 46 additions & 0 deletions build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -414,5 +414,51 @@ pub static SETTINGS_META: Lazy<IndexMap<&'static str, SettingsMeta>> = Lazy::new
.to_string(),
);

// Generate MisercSettings struct for early initialization settings
lines.push(
r#"
/// Settings that can be set in .miserc.toml for early initialization.
/// These settings affect config file discovery and must be loaded before
/// the main config files are parsed.
#[derive(Debug, Clone, Default, serde::Deserialize)]
pub struct MisercSettings {"#
.to_string(),
);

for (key, props) in &settings {
let props = props.as_table().unwrap();
// Only include settings with rc = true
if props
.get("rc")
.is_some_and(|v| v.as_bool().unwrap_or(false))
{
if let Some(description) = props.get("description") {
lines.push(format!(" /// {}", description.as_str().unwrap()));
}
let type_ = props
.get("rust_type")
.map(|rt| rt.as_str().unwrap())
.or(props.get("type").map(|t| match t.as_str().unwrap() {
"Bool" => "bool",
"String" => "String",
"Integer" => "i64",
"Url" => "String",
"Path" => "PathBuf",
"Duration" => "String",
"ListString" => "Vec<String>",
"ListPath" => "Vec<PathBuf>",
"SetString" => "BTreeSet<String>",
"IndexMap<String, String>" => "IndexMap<String, String>",
t => panic!("Unknown type: {t}"),
}));
if let Some(type_) = type_ {
// All miserc settings are optional
let type_ = format!("Option<{type_}>");
lines.push(format!(" pub {key}: {type_},"));
}
}
}
lines.push("}".to_string());

fs::write(&dest_path, lines.join("\n")).unwrap();
}
32 changes: 29 additions & 3 deletions docs/configuration/environments.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,35 @@
# Config Environments

It's possible to have separate `mise.toml` files in the same directory for different
environments like `development` and `production`. To enable, either set the `-E,--env` option or `MISE_ENV` environment
variable to an environment like `development` or `production`. mise will then look for a `mise.{MISE_ENV}.toml` file
in the current directory, parent directories and the `MISE_CONFIG_DIR` directory.
environments like `development` and `production`. To enable, set `MISE_ENV` to an
environment like `development` or `production` using one of these methods:

- CLI flag: `-E development` or `--env development`
- Environment variable: `MISE_ENV=development`
- `.miserc.toml` file: `env = ["development"]`

mise will then look for a `mise.{MISE_ENV}.toml` file in the current directory,
parent directories and the `MISE_CONFIG_DIR` directory.

## Setting MISE_ENV in .miserc.toml

You can set `MISE_ENV` in a `.miserc.toml` file, which is loaded very early before
other config files are discovered. This allows you to commit your environment
configuration to version control:

```toml
# .miserc.toml
env = ["development"]
```

File locations searched (in order of precedence):

1. `.miserc.toml` in current directory and parent directories
2. `~/.config/mise/miserc.toml` (global)
3. `/etc/mise/miserc.toml` (system)

Note: `MISE_ENV` cannot be set in `mise.toml` because it determines which config
files to load in the first place.

mise will also look for "local" files like `mise.local.toml` and `mise.{MISE_ENV}.local.toml`
in the current directory and parent directories.
Expand Down
25 changes: 25 additions & 0 deletions e2e/config/test_miserc
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#!/usr/bin/env bash
# shellcheck disable=SC2209

# Test that .miserc.toml can set MISE_ENV

echo "tools.dummy = '1'" >mise.toml
echo "tools.dummy = '2'" >mise.test.toml
echo 'env = ["test"]' >.miserc.toml

# .miserc.toml should set MISE_ENV=test, loading mise.test.toml
assert "mise ls dummy" "dummy 2.0.0 (missing) ~/workdir/mise.test.toml 2"

# Env var should override .miserc.toml
MISE_ENV=ci assert "mise ls dummy" "dummy 1.1.0 (missing) ~/workdir/mise.toml 1"

# Test ceiling_paths in .miserc.toml - subdirectory should pick up parent miserc
rm -f .miserc.toml
Copy link

Copilot AI Jan 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test removes .miserc.toml on line 17 and immediately recreates it on line 18 with identical content. This appears to be redundant—consider removing line 17 or clarifying with a comment if this serves a specific testing purpose.

Suggested change
rm -f .miserc.toml

Copilot uses AI. Check for mistakes.
echo 'env = ["test"]' >.miserc.toml
mkdir -p subdir
cd subdir || exit 1

# Should still pick up parent .miserc.toml and mise.test.toml
assert "mise ls dummy" "dummy 2.0.0 (missing) ~/workdir/mise.test.toml 2"

cd .. || exit 1
4 changes: 4 additions & 0 deletions schema/mise-settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,10 @@
],
"description": "How to parse the environment variable value"
},
"rc": {
"type": "boolean",
"description": "Whether this setting can be set in .miserc.toml for early initialization"
},
"rust_type": {
"type": "string",
"description": "Rust type used internally for this setting"
Expand Down
12 changes: 10 additions & 2 deletions schema/mise.json
Original file line number Diff line number Diff line change
Expand Up @@ -489,6 +489,14 @@
"description": "Path to change to after launching mise",
"type": "string"
},
"ceiling_paths": {
"default": [],
"description": "Directories where mise stops searching for config files.",
"type": "array",
"items": {
"type": "string"
}
},
"ci": {
"default": "false",
"description": "Set to true if running in a CI environment",
Expand Down Expand Up @@ -855,15 +863,15 @@
},
"override_config_filenames": {
"default": [],
"description": "If set, mise will ignore default config files like `mise.toml` and use these filenames instead. This must be an env var.",
"description": "If set, mise will ignore default config files like `mise.toml` and use these filenames instead.",
"type": "array",
"items": {
"type": "string"
}
},
"override_tool_versions_filenames": {
"default": [],
"description": "If set, mise will ignore .tool-versions files and use these filenames instead. Can be set to `none` to disable .tool-versions. This must be an env var.",
"description": "If set, mise will ignore .tool-versions files and use these filenames instead. Can be set to `none` to disable .tool-versions.",
"type": "array",
"items": {
"type": "string"
Expand Down
49 changes: 49 additions & 0 deletions schema/miserc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "mise rc config",
"description": "Early initialization settings for mise. These settings are loaded before the main config files.",
"type": "object",
"additionalProperties": false,
"properties": {
"ceiling_paths": {
"default": [],
"description": "Directories where mise stops searching for config files.",
"type": "array",
"items": {
"type": "string"
}
},
"env": {
"default": [],
"description": "Env to use for mise.<MISE_ENV>.toml files.",
"type": "array",
"items": {
"type": "string"
}
},
"ignored_config_paths": {
"default": [],
"description": "This is a list of config paths that mise will ignore.",
"type": "array",
"items": {
"type": "string"
}
},
"override_config_filenames": {
"default": [],
"description": "If set, mise will ignore default config files like `mise.toml` and use these filenames instead.",
"type": "array",
"items": {
"type": "string"
}
},
"override_tool_versions_filenames": {
"default": [],
"description": "If set, mise will ignore .tool-versions files and use these filenames instead. Can be set to `none` to disable .tool-versions.",
"type": "array",
"items": {
"type": "string"
}
}
}
}
56 changes: 54 additions & 2 deletions settings.toml
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,27 @@ hide = true
optional = true
type = "Path"

[ceiling_paths]
default = []
description = "Directories where mise stops searching for config files."
docs = """
Directories where mise stops searching for config files. By default, mise
will search from the current directory up to the root of the filesystem.

Setting this to a list of directories will stop the search when one of
those directories is reached. This is useful to prevent mise from searching
outside of a project directory.

This is an early-init setting: it must be set in `.miserc.toml`, environment
variables, or CLI flags. Setting it in `mise.toml` will have no effect because
config file discovery has already occurred by the time `mise.toml` is read.
"""
env = "MISE_CEILING_PATHS"
parse_env = "list_by_colon"
rc = true
rust_type = "BTreeSet<PathBuf>"
type = "ListPath"

[ci]
default = "false"
description = "Set to true if running in a CI environment"
Expand Down Expand Up @@ -373,9 +394,14 @@ to use this feature.

Multiple envs can be set by separating them with a comma, e.g. `MISE_ENV=ci,test`.
They will be read in order, with the last one taking precedence.

This is an early-init setting: it must be set in `.miserc.toml`, environment
variables, or CLI flags (`-E`/`--env`). Setting it in `mise.toml` will have no
effect because `MISE_ENV` determines which config files to load.
"""
env = "MISE_ENV"
parse_env = "list_by_comma"
rc = true
type = "ListString"

[env_file]
Expand Down Expand Up @@ -658,8 +684,16 @@ type = "SetString"
[ignored_config_paths]
default = []
description = "This is a list of config paths that mise will ignore."
docs = """
This is a list of config paths that mise will ignore.

This is an early-init setting: it must be set in `.miserc.toml`, environment
variables, or CLI flags. Setting it in `mise.toml` will have no effect because
config file discovery has already occurred by the time `mise.toml` is read.
"""
env = "MISE_IGNORED_CONFIG_PATHS"
parse_env = "list_by_colon"
rc = true
rust_type = "BTreeSet<PathBuf>"
type = "ListPath"

Expand Down Expand Up @@ -907,16 +941,34 @@ type = "String"

[override_config_filenames]
default = []
description = "If set, mise will ignore default config files like `mise.toml` and use these filenames instead. This must be an env var."
description = "If set, mise will ignore default config files like `mise.toml` and use these filenames instead."
docs = """
If set, mise will ignore default config files like `mise.toml` and use these
filenames instead.

This is an early-init setting: it must be set in `.miserc.toml`, environment
variables, or CLI flags. Setting it in `mise.toml` will have no effect because
config file discovery has already occurred by the time `mise.toml` is read.
"""
env = "MISE_OVERRIDE_CONFIG_FILENAMES"
parse_env = "list_by_colon"
rc = true
type = "ListString"

[override_tool_versions_filenames]
default = []
description = "If set, mise will ignore .tool-versions files and use these filenames instead. Can be set to `none` to disable .tool-versions. This must be an env var."
description = "If set, mise will ignore .tool-versions files and use these filenames instead. Can be set to `none` to disable .tool-versions."
docs = """
If set, mise will ignore .tool-versions files and use these filenames instead.
Can be set to `none` to disable .tool-versions entirely.

This is an early-init setting: it must be set in `.miserc.toml`, environment
variables, or CLI flags. Setting it in `mise.toml` will have no effect because
config file discovery has already occurred by the time `mise.toml` is read.
"""
env = "MISE_OVERRIDE_TOOL_VERSIONS_FILENAMES"
parse_env = "list_by_colon"
rc = true
type = "ListString"

[paranoid]
Expand Down
5 changes: 5 additions & 0 deletions src/cli/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -557,6 +557,11 @@ fn preprocess_args_for_naked_run(cmd: &clap::Command, args: &[String]) -> Vec<St
impl Cli {
pub async fn run(args: &Vec<String>) -> Result<()> {
crate::env::ARGS.write().unwrap().clone_from(args);
// Load .miserc.toml early, before MISE_ENV and other early settings are accessed.
// This allows setting MISE_ENV in a config file instead of only via env vars.
if let Err(err) = crate::config::miserc::init() {
warn!("Failed to load .miserc.toml: {err}");
}
if *crate::env::MISE_TOOL_STUB && args.len() >= 2 {
tool_stub::short_circuit_stub(&args[2..]).await?;
}
Expand Down
Loading
Loading