Skip to content

Designing Your Workflow

You’ve met the pieces — tools, env, tasks, hooks. This page assembles them into a workflow a whole team can share: one committed config, a one-command onboard, a clear trust boundary, and a monorepo layout that scales.

The goal is boring in the best way — every dev and every CI runner gets the identical toolchain, env, and tasks from one source of truth.

A team's mise setup
Rendering diagram…

The rule: commit the shared truth, gitignore the personal overrides.

  • Directorymy-app/
    • mise.toml commit — tools, env, tasks for everyone
    • mise.lock commit — exact versions + checksums (see Tools & Backends)
    • mise.local.toml gitignored — your machine-only overrides
    • .gitignore
.gitignore
# personal, machine-specific overrides — never shared
*.local.toml
mise.toml (committed)
[settings]
lockfile = true # keep mise.lock in sync on every install/use
locked = true # plain `mise install` is strict — fail on missing platform URL
[tools]
node = "22"
python = "3.13"
[env]
DATABASE_URL = { default = "postgres://localhost:5432/myapp_dev" }
[tasks.setup]
description = "First-time project setup"
run = ["npm install", "npm run db:migrate"]

A dev who wants Node 22.14 specifically, or a different local DB, drops a mise.local.toml — it wins over mise.toml but never leaves their machine. (Full precedence table in Environments & Secrets.)

Replace the README’s “first install nvm, then pyenv, then…” wall with one script.

scripts/bootstrap.sh
#!/usr/bin/env bash
set -euo pipefail
# 1. install mise if it's missing
command -v mise >/dev/null || curl https://mise.run | sh
export PATH="$HOME/.local/bin:$PATH"
# 2. trust THIS repo's config (it can execute code — see below)
mise trust
# 3. install the exact pinned toolchain
mise install --locked
# 4. run project setup (deps, migrations, …)
mise run setup
Terminal window
git clone git@github.com:acme/my-app && cd my-app
./scripts/bootstrap.sh

That’s the whole onboarding doc. New laptop to running app in one command, and every step is reproducible from the committed config.

A mise.toml can run arbitrary code — env templates, _.source scripts, hooks, templated tasks. So when you cd into a repo you cloned, mise will not execute any of that until you’ve trusted the config. Plain [tools] and non-templated tasks load without prompting; anything that can run code is gated.

Trust gate
Rendering diagram…
Terminal window
mise trust # trust the config in/above the current dir
mise trust -a # trust everything (use sparingly)
mise trust --untrust # revoke
mise trust --show # what's trusted and why
mise doctor # lists untrusted configs it found

Trust state lives in ~/.local/state/mise/, keyed by path — trusting one repo says nothing about another. For a monorepo, monorepo_root = true means trusting the root also trusts its descendant configs.

Knobs worth knowing:

SettingEffect
trusted_config_paths = ["/"]trust everything under a path (e.g. all of ~/work)
MISE_PARANOID=1paranoid mode — stricter trust checks, re-confirm more aggressively

The task-driven dev loop (goodbye Makefile)

Section titled “The task-driven dev loop (goodbye Makefile)”

Your Makefile / wall of npm scripts becomes [tasks] in the same file that pins your tools — so a task always runs with the right toolchain on PATH. Full task mechanics live in The Task Runner; here’s the team shape:

mise.toml
[tasks.setup]
description = "One-time setup after clone"
run = ["npm ci", "mise run db:migrate"]
[tasks.dev]
description = "Run the app with reload"
run = "npm run dev"
[tasks.test]
description = "Run the suite"
run = "npm test"
[tasks.lint]
run = "eslint ."
[tasks.check]
description = "What CI runs"
depends = ["lint", "test"]
Terminal window
mise run dev # everyone's "start working" command
mise run check # same gate locally and in CI
mise tasks # discoverable — no Makefile archaeology

The win over make: tasks are self-documenting (mise tasks), run under the pinned tools automatically, and are the exact commands CI runs. No “works-on-my-machine” because the toolchain isn’t pinned.

mise’s monorepo support is stable in 2026 (formerly the experimental experimental_monorepo_root). Declare a root and where the sub-project configs live — automatic filesystem-walk discovery is deprecated, so list them explicitly:

mise.toml (repo root)
monorepo_root = true
[monorepo]
config_roots = ["packages/*", "services/*"] # single-level glob; ** is NOT supported
[tools]
# shared toolchain for the whole monorepo
node = "22"

Each config_root carries its own mise.toml and merges with the root. Then address tasks from anywhere:

Monorepo task addressing
Rendering diagram…
AddressMeans
//packages/web:buildabsolute — the build task in packages/web
:testthe test task in the current config root
//...:lintthe lint task in every project, any depth
//services/*:testtest in each matching project (name wildcard)
Terminal window
mise run //...:lint # lint the whole monorepo
mise run //services/api:test # one project's tests
mise run :dev # the current project's dev task

Cross-project dependencies use the same addressing — a services/api task can depends = ["//packages/shared:build"] and mise builds shared first.

Node front-end, Python service, Go service, and Postgres client tooling — one repo, one toolchain truth.

  • Directoryshop/
    • mise.toml root: monorepo_root, shared base
    • mise.lock
    • Directorypackages/
      • Directoryweb/
        • mise.toml Node app
    • Directoryservices/
      • Directorybilling/
        • mise.toml Python service
      • Directoryinventory/
        • mise.toml Go service
    • docker-compose.yml the actual Postgres daemon
shop/mise.toml
monorepo_root = true
[settings]
lockfile = true
locked = true
[monorepo]
config_roots = ["packages/*", "services/*"]
[tools]
# language tooling shared across every project
node = "22"
[tasks."db:migrate"]
description = "Apply migrations against the docker-compose Postgres"
run = "docker compose exec -T db psql -U postgres shop_dev -f /migrations/latest.sql"
[env]
DATABASE_URL = { default = "postgres://localhost:5432/shop_dev" }

Now the whole repo answers to a handful of commands:

Terminal window
mise run //...:test # every project's tests, in parallel
mise run //packages/web:dev # just the front-end
mise run :test # current project (run from inside it)
  1. Wire this into CI and ship slim Docker images — CI, Docker & IDEs.
  2. Coming from asdf/nvm/direnv/make? — Migrating off the old tools.
  3. Deepen the task layer (incremental builds, args, watch) — The Task Runner.