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
41 changes: 21 additions & 20 deletions docs/tasks/monorepo.md
Original file line number Diff line number Diff line change
Expand Up @@ -224,34 +224,35 @@ run = "npm run build" # Uses node 20 and LOG_LEVEL=info from root
2. **Subdirectory override**: Tools and environment defined in the subdirectory's config file are merged on top, allowing overrides
3. **Task-specific tools and environment**: Values defined in the task's `tools` and `env` properties take highest precedence

## Performance Tuning
## Config Roots

For large monorepos, you can control task discovery depth with the `task.monorepo_depth` setting (default: 5):
You must explicitly list your config roots using the `[monorepo]` section:

```toml
[settings]
task.monorepo_depth = 3 # Only search 3 levels deep
```

This limits how deep mise will search for task files:

- `1` = immediate children only (`monorepo_root/projects/`)
- `2` = grandchildren (`monorepo_root/projects/frontend/`)
- `5` = default (5 levels deep)
# /myproject/mise.toml
experimental_monorepo_root = true

Reduce this value if you notice slow task discovery in very large monorepos, especially if your projects are concentrated at a specific depth level.
[monorepo]
config_roots = [
"packages/frontend",
"packages/backend",
"services/*", # Single-level glob pattern
]
```

## Discovery Behavior
This tells mise exactly which directories contain project configurations. Benefits:

### Excluded Paths
- **Fast discovery**: No filesystem walking needed
- **Explicit control**: Only the projects you list are included
- **Glob support**: Use `*` for single-level patterns (e.g., `services/*` matches `services/api`, `services/worker`)

The following directories are automatically excluded from task discovery:
::: tip
Single-level globs (`*`) are supported, but recursive globs (`**`) are not. This ensures predictable performance while still allowing flexible patterns.
:::

- Hidden directories (starting with `.`)
- `node_modules`
- `target`
- `dist`
- `build`
::: warning Automatic Discovery Deprecated
Automatic filesystem walking to discover monorepo subdirectories is deprecated. If you don't define `[monorepo].config_roots`, mise will still walk the filesystem but will emit a deprecation warning. Please migrate to explicit config roots.

Copilot AI Jan 17, 2026

Copy link

Choose a reason for hiding this comment

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

The deprecation notice should include information about when this feature will be removed (if planned) to help users understand the urgency of migrating.

Suggested change
Automatic filesystem walking to discover monorepo subdirectories is deprecated. If you don't define `[monorepo].config_roots`, mise will still walk the filesystem but will emit a deprecation warning. Please migrate to explicit config roots.
Automatic filesystem walking to discover monorepo subdirectories is deprecated. If you don't define `[monorepo].config_roots`, mise will still walk the filesystem but will emit a deprecation warning. Please migrate to explicit config roots. There is currently no scheduled removal date for this behavior, but it may be removed in a future major release, so plan your migration accordingly.

Copilot uses AI. Check for mistakes.
:::

## Listing Tasks

Expand Down
3 changes: 3 additions & 0 deletions e2e/tasks/test_task_colon_syntax
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ export MISE_EXPERIMENTAL=1
cat <<'EOF' >mise.toml
experimental_monorepo_root = true

[monorepo]
config_roots = ["project", "app"]

[tasks.build]
run = 'echo "root build task"'
EOF
Expand Down
3 changes: 3 additions & 0 deletions e2e/tasks/test_task_info_monorepo
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
cat >mise.toml <<EOF
experimental_monorepo_root = true

[monorepo]
config_roots = ["lib"]

[tasks.root_task]
alias = "some_root_task_alias"
run = "echo This is the root task"
Expand Down
3 changes: 3 additions & 0 deletions e2e/tasks/test_task_ls_complete_monorepo
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
cat <<'CONFIG' >mise.toml
experimental_monorepo_root = true

[monorepo]
config_roots = ["apps/*"]

[tasks.root-task]
run = 'echo root'
CONFIG
Expand Down
9 changes: 9 additions & 0 deletions e2e/tasks/test_task_monorepo_aliases
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ export MISE_EXPERIMENTAL=1
cat <<'TOML' >mise.toml
experimental_monorepo_root = true

[monorepo]
config_roots = ["projects/*"]

[tasks.format]
alias = "fmt"
run = "echo 'formatting code'"
Expand Down Expand Up @@ -61,6 +64,9 @@ echo "$output" | grep -q "building backend" || (echo "FAIL: Nested task alias di
cat <<'TOML' >mise.toml
experimental_monorepo_root = true

[monorepo]
config_roots = ["projects/*"]

[tasks.format]
alias = "fmt"
run = "echo 'formatting code'"
Expand All @@ -80,6 +86,9 @@ echo "$output" | grep -q "deploying" || (echo "FAIL: Dependent task did not run"
cat <<'TOML' >mise.toml
experimental_monorepo_root = true

[monorepo]
config_roots = ["projects/*"]

[tasks.format]
alias = "fmt"
run = "echo 'formatting code'"
Expand Down
3 changes: 3 additions & 0 deletions e2e/tasks/test_task_monorepo_circular_deps
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ export MISE_EXPERIMENTAL=1
cat <<EOF >mise.toml
experimental_monorepo_root = true

[monorepo]
config_roots = ["projects/*"]

[tasks.root-task]
run = 'echo "root task"'
EOF
Expand Down
3 changes: 3 additions & 0 deletions e2e/tasks/test_task_monorepo_config_context
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ export MISE_NODE_VERIFY=0 # Skip GPG verification to avoid keyboxd issues
cat <<EOF >mise.toml
experimental_monorepo_root = true

[monorepo]
config_roots = ["projects/*", "libs/*"]

[env]
ROOT_VAR = "root_value"
SHARED_VAR = "root_shared"
Expand Down
88 changes: 88 additions & 0 deletions e2e/tasks/test_task_monorepo_config_roots
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
#!/usr/bin/env bash
# Test [monorepo].config_roots for explicit config root listing
export MISE_EXPERIMENTAL=1

# Create monorepo root config with explicit config_roots
cat <<'TOML' >mise.toml
experimental_monorepo_root = true

[monorepo]
config_roots = [
"packages/frontend",
"packages/backend",
"services/*",
]

[tasks.root]
run = 'echo "root task"'
TOML

# Create packages that ARE in config_roots
mkdir -p packages/frontend
cat <<'TOML' >packages/frontend/mise.toml
[tasks.build]
run = 'echo "frontend build"'
TOML

mkdir -p packages/backend
cat <<'TOML' >packages/backend/mise.toml
[tasks.build]
run = 'echo "backend build"'
TOML

# Create services/* for glob test
mkdir -p services/api
cat <<'TOML' >services/api/mise.toml
[tasks.serve]
run = 'echo "api serve"'
TOML

mkdir -p services/worker
cat <<'TOML' >services/worker/mise.toml
[tasks.process]
run = 'echo "worker process"'
TOML

# Create a package that is NOT in config_roots (should NOT be discovered)
mkdir -p packages/ignored
cat <<'TOML' >packages/ignored/mise.toml
[tasks.hidden]
run = 'echo "this should not appear"'
TOML

# Create another directory that is NOT in config_roots
mkdir -p libs/common
cat <<'TOML' >libs/common/mise.toml
[tasks.test]
run = 'echo "this should not appear either"'
TOML

# Test 1: Listed explicit paths are discovered
echo "=== Test 1: Explicit paths are discovered ==="
output=$(mise tasks --all 2>&1)
echo "$output"
echo "$output" | grep -q "//packages/frontend:build" || (echo "FAIL: frontend not found" && exit 1)
echo "$output" | grep -q "//packages/backend:build" || (echo "FAIL: backend not found" && exit 1)

# Test 2: Glob patterns work (services/*)
echo "=== Test 2: Glob patterns work ==="
echo "$output" | grep -q "//services/api:serve" || (echo "FAIL: services/api not found via glob" && exit 1)
echo "$output" | grep -q "//services/worker:process" || (echo "FAIL: services/worker not found via glob" && exit 1)

# Test 3: Unlisted paths are NOT discovered
echo "=== Test 3: Unlisted paths are not discovered ==="
if echo "$output" | grep -q "//packages/ignored:hidden"; then
echo "FAIL: packages/ignored should NOT be discovered"
exit 1
fi
if echo "$output" | grep -q "//libs/common:test"; then
echo "FAIL: libs/common should NOT be discovered"
exit 1
fi

# Test 4: Tasks can still be run
echo "=== Test 4: Tasks can be run ==="
mise run '//packages/frontend:build' | grep -q "frontend build" || (echo "FAIL: couldn't run frontend task" && exit 1)
mise run '//services/api:serve' | grep -q "api serve" || (echo "FAIL: couldn't run api task" && exit 1)

echo "=== All config_roots tests passed! ==="
3 changes: 3 additions & 0 deletions e2e/tasks/test_task_monorepo_dependencies
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ export MISE_EXPERIMENTAL=1
cat <<'TOML' >mise.toml
experimental_monorepo_root = true

[monorepo]
config_roots = ["projects/*"]

[tasks.root-setup]
run = 'echo "root-setup-done" > /tmp/root-setup.txt'
TOML
Expand Down
3 changes: 3 additions & 0 deletions e2e/tasks/test_task_monorepo_dependency_chain
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ export MISE_EXPERIMENTAL=1
# Create monorepo root config
cat <<'TOML' >mise.toml
experimental_monorepo_root = true

[monorepo]
config_roots = ["ProjectA", "ProjectB"]
TOML

# Create ProjectB with a build task
Expand Down
3 changes: 3 additions & 0 deletions e2e/tasks/test_task_monorepo_deps
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ cat <<'EOF' >mise.toml
min_version = "2025.10.6"
experimental_monorepo_root = true

[monorepo]
config_roots = ["submodule", "project", "other"]

[settings]
experimental = true
EOF
Expand Down
3 changes: 3 additions & 0 deletions e2e/tasks/test_task_monorepo_dots_in_dir
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ export MISE_EXPERIMENTAL=1
cat <<'TOML' >mise.toml
experimental_monorepo_root = true

[monorepo]
config_roots = ["projects/*"]

[tasks.root-task]
run = 'echo "root task executed"'
TOML
Expand Down
3 changes: 3 additions & 0 deletions e2e/tasks/test_task_monorepo_edge_cases
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ export MISE_EXPERIMENTAL=1
cat <<EOF >mise.toml
experimental_monorepo_root = true

[monorepo]
config_roots = ["projects/*"]

[tasks.root-task]
run = 'echo "root task"'
EOF
Expand Down
3 changes: 3 additions & 0 deletions e2e/tasks/test_task_monorepo_env_version_override
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ export MISE_EXPERIMENTAL=1
cat <<EOF >mise.toml
experimental_monorepo_root = true

[monorepo]
config_roots = ["projects/*"]

[tools]
tiny = "2.0.0"

Expand Down
6 changes: 6 additions & 0 deletions e2e/tasks/test_task_monorepo_errors
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ echo "=== Test 1: Malformed config in subdirectory ==="
cat <<'TOML' >mise.toml
experimental_monorepo_root = true

[monorepo]
config_roots = ["projects/*"]

[tasks.root-task]
run = 'echo "root task works"'
TOML
Expand Down Expand Up @@ -105,6 +108,9 @@ export MISE_EXPERIMENTAL=1
cat <<'TOML' >mise.toml
experimental_monorepo_root = true

[monorepo]
config_roots = ["projects/*"]

[tasks.root-task]
run = 'echo "root"'
TOML
Expand Down
3 changes: 3 additions & 0 deletions e2e/tasks/test_task_monorepo_file_tasks
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ export MISE_EXPERIMENTAL=1
cat <<EOF >mise.toml
experimental_monorepo_root = true

[monorepo]
config_roots = ["projects/*"]

[tasks.root-task]
run = 'echo "root task"'
EOF
Expand Down
3 changes: 3 additions & 0 deletions e2e/tasks/test_task_monorepo_includes
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ export MISE_EXPERIMENTAL=1
cat <<EOF >mise.toml
experimental_monorepo_root = true

[monorepo]
config_roots = ["projects/*"]

[tasks.root-task]
run = 'echo "root task"'
EOF
Expand Down
3 changes: 3 additions & 0 deletions e2e/tasks/test_task_monorepo_mise_env
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ export MISE_EXPERIMENTAL=1
cat <<EOF >mise.toml
experimental_monorepo_root = true

[monorepo]
config_roots = ["projects/*"]

[env]
ROOT_VAR = "root_value"
ENV_VAR = "root_default"
Expand Down
3 changes: 3 additions & 0 deletions e2e/tasks/test_task_monorepo_name_conflicts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ export MISE_EXPERIMENTAL=1
cat <<EOF >mise.toml
experimental_monorepo_root = true

[monorepo]
config_roots = ["projects/frontend"]

[tasks.build]
run = 'echo "root build"'
EOF
Expand Down
3 changes: 3 additions & 0 deletions e2e/tasks/test_task_monorepo_nested_config
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ export MISE_EXPERIMENTAL=1
# Create monorepo root config
cat <<'TOML' >mise.toml
experimental_monorepo_root = true

[monorepo]
config_roots = ["projects/*"]
TOML

# Create subdirectory with NESTED config path (.config/mise/config.toml)
Expand Down
3 changes: 3 additions & 0 deletions e2e/tasks/test_task_monorepo_optional_colon
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ cat <<'EOF' >mise.toml
min_version = "2025.10.6"
experimental_monorepo_root = true

[monorepo]
config_roots = ["app", "frontend", "backend", "services", "other"]

[settings]
experimental = true
EOF
Expand Down
3 changes: 3 additions & 0 deletions e2e/tasks/test_task_monorepo_path_directives
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ export MISE_EXPERIMENTAL=1
cat <<EOF >mise.toml
experimental_monorepo_root = true

[monorepo]
config_roots = ["projects/*"]

[env]
_.path = ["./root-bin"]

Expand Down
3 changes: 3 additions & 0 deletions e2e/tasks/test_task_monorepo_relative_paths
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ export MISE_EXPERIMENTAL=1
cat <<EOF >mise.toml
experimental_monorepo_root = true

[monorepo]
config_roots = ["projects/*"]

[env]
ROOT_DATA = "./root-data.txt"

Expand Down
3 changes: 3 additions & 0 deletions e2e/tasks/test_task_monorepo_run_project_local_tasks
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ export MISE_EXPERIMENTAL=1

cat <<'TOML' >mise.toml
experimental_monorepo_root = true

[monorepo]
config_roots = ["projects/backend"]
TOML

mkdir -p projects/backend
Expand Down
Loading
Loading