| name | mise-task-managing |
| description | Conventions for creating and managing development workflow tasks.Use 1) when asked to create a mise task, 2) when adding a tasks to node package file, pnpm, bun, 3) when creating or modifying a script, 4) to encapsulate a complex workflow or chain of commands. |
Mise Task Conventions
Mandatory
- Every project root MUST contain a
mise.toml
- If a project root does NOT contain a
mise.toml then copy the base to the project root as mise.toml
Progressive Discovery Reference Map
When you see a relevant match to your current task, STOP!
Read no further and load the applicable reference.
-
Are you starting a fresh project? See starting-fresh
-
Are you integrating mise in a brownfield project? See brownfield
-
Were you asked to encapsulate a multi-step custom workflow? See custom-workflows
-
Did you create a new script, add a new CLI command, or get asked to expose or make available any of the former as a convenience task? See wraping-an-interface
-
Are you implementing or adapting one of the supported common workflows (Database, Build, CI, Test, Deploy, Lint)? See common-workflows
If you didn't find a match, here are the general rules to follow
- If defining a simple task like a one-liner, use TOML Tasks
Then, define tasks directly in mise.toml under the [tasks.*] section:
[tasks.build]
description = "Build the project"
run = "cargo build"
[tasks.test]
description = "Run tests"
run = "cargo test"
depends = ["build"]
Execute: mise run build or mise build
- If your task is multi-line and looks more like inline code, use File Tasks
Implement the task as an executable shell or python script in .mise/tasks/ directory:
#!/usr/bin/env bash
cargo build
Place in .mise/tasks/build (no extension), make executable, and run identically: mise run build
- Configuration File Structure
project-root/
├── mise.toml # Primary config with [tasks.*] section
├── .mise/tasks/ # Directory for file-based tasks
│ ├── build # Executable task script
│ ├── test # Executable task script
│ └── deploy # Executable task script
- TOML Task Structure
[tasks.task-name]
description = "Task description shown in mise tasks"
run = "command to execute"
depends = ["other-task"]
env = { VAR = "value" }
dir = "{{ config_root }}"
sources = ["src/**/*.rs"]
outputs = ["target/release/binary"]
- File Task Metadata
Use #MISE comments for task configuration:
#!/usr/bin/env bash
./deploy.sh
- Task Configuration Options
Essential Fields:
run (TOML tasks only, required)
- String:
run = "cargo build"
- Array:
run = ["cargo build", "cargo test"]
- Mixed with task refs:
run = [{ task = "lint" }, "cargo build"]
description
- Used in help output, completions, and
mise tasks listing
- Visible to users as documentation
depends
- Tasks that run before this task
depends = ["lint", "test"]
depends_post
- Tasks that run after this task completes
depends_post = ["cleanup"]
- Environment & Execution
env
- Task-specific environment variables
- Not propagated to dependent tasks
env = { NODE_ENV = "production", API_KEY = "secret" }
tools
- Tools to install/activate before task
- Only for this task, not dependencies
tools = ["node@20", "python@3.12"]
dir
- Working directory for execution
- Default:
"{{ config_root }}" (where mise.toml lives)
dir = "{{ cwd }}/subdir"
shell
- Override default shell for inline execution
- TOML tasks only
shell = "bash -c"
- Caching with Sources & Outputs
sources
- Input files/globs that this task uses
- Mise skips execution if sources unchanged and outputs are newer
sources = ["src/**/*.rs", "Cargo.toml"]
outputs
- Output files/directories produced by task
- Enable automatic change detection with
outputs = [{ auto = true }]
outputs = ["target/release/binary"]
Caching behavior:
- Mise compares modification times of oldest output vs newest source
- If outputs are newer, task is skipped
- Use
mise run --force to bypass cache
- Control & Visibility
hide
- Hide from
mise tasks output, help, and completions
- Useful for internal/deprecated tasks
hide = true
quiet
- Suppress mise's own output (like command being run)
quiet = true
silent
- Suppress all task output
- Options:
true (both), "stdout", "stderr"
silent = "stdout"
raw
- Connect task directly to shell stdin/stdout/stderr
- Disables parallel execution
- Required for interactive tasks
raw = true
confirm
- Prompt user before running
confirm = "Are you sure you want to deploy?"
- Advanced: Task Arguments
Define formal arguments and flags in usage field:
[tasks.deploy]
run = "deploy.sh"
usage = """
{usage} [OPTIONS] <environment>
Arguments:
<environment> Target environment [env: ENVIRONMENT]
Options:
--force Skip confirmation
"""
Running Tasks
Basic Execution
mise run task-name
mise r task-name
mise task-name
Passing Arguments
Extra arguments pass through to the task:
mise run build --release
mise run test -- --nocapture
Multiple Tasks
Run sequentially:
mise run lint build test
Run separate sequences with ::: delimiter:
mise run build arg1 ::: test arg2
- Advanced: Parallel Execution
Default: 4 parallel jobs. Control via:
--jobs N flag
MISE_JOBS environment variable
jobs setting in mise.toml
mise run -j 8 task1 task2 task3
Output is line-prefixed to prevent interleaving. Use --interleave for direct stdout/stderr.
- Listing Tasks
mise tasks
mise tasks --hidden
mise tasks deps [tasks]...
- Watching for Changes
mise watch task-name
Uses watchexec internally to monitor source files.
- Common Pattern: Task Orchestration
[tasks.ci]
description = "Run CI checks"
depends = ["lint", "test", "build"]
[tasks.deploy]
description = "Deploy application"
depends = ["ci"]
depends_post = ["notify"]
run = "./deploy.sh"
- Common Pattern: Environment-Specific Tasks
[tasks.build]
description = "Build for development"
run = "npm run build"
env = { NODE_ENV = "development" }
[tasks."build:prod"]
description = "Build for production"
run = "npm run build"
env = { NODE_ENV = "production" }
- Common Pattern: Conditional Execution with Sources
[tasks.compile]
description = "Compile only if sources changed"
run = "gcc src/*.c -o bin/app"
sources = ["src/*.c", "src/*.h"]
outputs = ["bin/app"]
- Common Pattern: File Task with Dependencies
#!/usr/bin/env bash
set -euo pipefail
echo "Running build..."
cargo build --release
echo "Running integration tests..."
cargo test --release
Cross-Language Task Runner
[tasks.backend]
description = "Start backend server"
dir = "{{ config_root }}/backend"
run = "cargo run"
[tasks.frontend]
description = "Start frontend dev server"
dir = "{{ config_root }}/frontend"
run = "npm run dev"
[tasks.dev]
description = "Start full development environment"
depends = ["backend", "frontend"]
- Mise automatically injects these globals:
MISE_ORIGINAL_CWD - Initial working directory
MISE_CONFIG_ROOT - Directory containing mise.toml
MISE_PROJECT_ROOT - Project root directory
MISE_TASK_NAME - Current task identifier
MISE_TASK_DIR - Task script location (file tasks)
MISE_TASK_FILE - Full task script path (file tasks)
- Workflow Command: Initialize Mise in Project
`cp ./references/base-mise.toml mise.toml`
mise trust
mise tasks
- Workflow Command: Convert Makefile to Mise Tasks
For projects with Makefiles, migrate to mise for better dependency management:
[tasks.install]
description = "Install dependencies"
run = "npm install"
[tasks.build]
description = "Build project"
depends = ["install"]
sources = ["src/**/*"]
outputs = ["dist/"]
run = "npm run build"
[tasks.test]
description = "Run tests"
depends = ["build"]
run = "npm test"
Benefits over Make:
- Automatic parallel execution
- Built-in file watching
- Cross-platform compatibility
- Better dependency management
Create File Task Script
mkdir -p .mise/tasks
cat > .mise/tasks/deploy <<'BASH'
set -euo pipefail
echo "Deploying to production..."
$MISE_PROJECT_ROOT/scripts/deploy.sh "$@"
BASH
chmod +x .mise/tasks/deploy
mise run deploy
- Best Practice: Task Naming
- Use semantic names:
build, test, deploy
- Group with colons:
test:unit, test:integration, test:e2e
- Wildcard support:
mise run test:* runs all test tasks
- Best Practice: Dependency Management
- Use
depends for prerequisites: depends = ["lint", "test"]
- Use
depends_post for cleanup: depends_post = ["notify"]
- Keep dependency chains shallow (2-3 levels max)
- Tasks run in parallel when possible
- Best Practice: Caching Strategy
- Define
sources for input files
- Define
outputs for generated artifacts
- Use globs for flexibility:
sources = ["src/**/*.rs"]
- Use
{ auto = true } for automatic output detection
- Best Practice: File Tasks vs TOML Tasks
Use File Tasks when:
- Script is >10 lines
- Complex bash logic required
- Multiple commands with error handling
- Script needs version control
Use TOML Tasks when:
- Simple one-liners
- Task orchestration (depends on other tasks)
- Environment variable setup
- Quick prototyping
- Best Practice: Error Handling
In TOML tasks:
[tasks.robust]
run = ["set -euo pipefail", "./script.sh"]
In File tasks:
#!/usr/bin/env bash
set -euo pipefail
- Troubleshooting: Tasks Not Appearing
Check:
-
Syntax errors in mise.toml: mise tasks --verbose
-
Missing description field
-
Task marked hide = true
-
Config not trusted: mise trust
-
Troubleshooting: Task Not Caching
Verify:
-
sources and outputs are defined
-
Globs match files: ls src/**/*.rs
-
Output files exist after task runs
-
Use mise run --force task-name to bypass cache once
-
Troubleshooting: File Task Not Executable
chmod +x mise-tasks/task-name
- Troubleshooting: Tasks Running in Wrong Directory
Set explicit working directory:
[tasks.task-name]
dir = "{{ config_root }}/subdir"
run = "make build"
- Troubleshooting: Parallel Execution Issues
For interactive tasks or tasks requiring stdin:
[tasks.interactive]
raw = true
run = "npm run dev"
Additional Resources