← Back to all posts

Mise en Place: The Art of Preparation

A practical walkthrough of the "holy grail" developer CLI, mise, and how it unifies tool version management, environment variables, and task running for a smoother dev experience

✍️ Dasho 📅 2026-02-22
documentation guide mise developer experience cli

The “holy grail” dev CLI, explained: a practical walkthrough of mise

I ran into the YouTube video titled “The Holy Grail of Developer CLIs” from the DevOps Toolbox channel a little while ago, and it hit a nerve in the best way. (YouTube)

The vibe is simple: most of us already juggle a pile of small tools to make local dev feel “normal”. A version manager here, some .env plumbing there, a task runner duct-taped on top. The video’s pitch is that mise pulls that scattered setup into one place.

I’m going to walk through the same core idea the video spotlights, then layer in concrete config examples so you can try it in a real repo. Along the way, I’ll sprinkle in the thoughts I had while reading up on the docs and seeing how the pieces fit.



Why this class of tool keeps showing up

If you’ve ever cloned a repo and immediately hit:

  • “You need Node 20, not Node 22”
  • “Oh, you also need terraform
  • “Set FOO_API_URL or nothing works”
  • “Run make dev… unless you’re on Windows… unless you use just… unless…”

…you already know the shape of the problem. Every team eventually invents a “developer experience stack”. It usually works, until it doesn’t. Then a new hire loses an afternoon to PATH issues.

What I liked about the video’s framing is that it doesn’t pretend we can avoid complexity. It argues we can centralize it.

That’s the whole hook of mise: it positions itself as the front-end for your dev environment. (GitHub)



What mise is trying to unify

The official description is almost cheeky because it maps to tools we all recognize:

  • Like asdf (or nvm, pyenv, and friends), it manages dev tool versions.
  • Like direnv, it manages project-level environment variables.
  • Like make, it manages tasks. (GitHub)

The video basically takes that mapping and says: “Stop stitching these together yourself.” (YouTube)

And yeah, that “one CLI to rule them all” idea sounds suspicious at first. I had the same reaction. I’ve been burned by “unifying tools” that become a new dependency you can’t escape.

What calmed me down here is that mise is doing fairly boring things, just in a coordinated way:

  • Pin versions per directory.
  • Export env vars when you enter that directory.
  • Provide a task runner that can see the same tools and env vars.

Boring is good. Boring is dependable.



Walkthrough: setting up a repo with mise

This walkthrough assumes a single repo that needs:

  • a pinned runtime
  • a couple of CLI tools
  • some env vars
  • a task flow that everyone can run the same way

You can adapt it to almost anything.

Step 1: Install mise

The docs list several install methods (Homebrew, apt, dnf, pacman, Scoop, winget, and more). (mise-en-place)

One common quick start looks like this:

curl https://mise.run | sh
~/.local/bin/mise --version

That command shows up in the project README too, along with the suggested shell hook. (GitHub)

Step 2: Hook it into your shell

To make per-directory switching work, you typically activate it in your shell profile:

# bash
echo 'eval "$(~/.local/bin/mise activate bash)"' >> ~/.bashrc

# zsh
echo 'eval "$(~/.local/bin/mise activate zsh)"' >> ~/.zshrc

(There are equivalent snippets for fish and PowerShell as well.) (GitHub)

This is the moment where I always pause and ask: “Am I about to let random repos execute stuff when I cd into them?” Good news: mise has an explicit trust model. We’ll get to that.



Step 3: Create a mise.toml and pin tool versions

In the root of your repo, create mise.toml:

# mise.toml
[tools]
node = "24"
python = "3.12"
terraform = "1"

A few notes:

  • mise supports lots of tools and can switch versions based on the directory you’re in. (mise-en-place)
  • The main workflow command is mise use. It installs (if needed) and writes the chosen version into mise.toml. (mise-en-place)

So instead of editing by hand, you can do:

mise use node@24
mise use python@3.12
mise use terraform@1

Then:

mise install

At this point, the repo has a single source of truth for versions.

Here’s the little dopamine hit: you stop thinking “what version am I supposed to have installed?” and start thinking “the repo tells me”.



Step 4: Run commands with pinned versions

Two patterns are worth knowing:

Pattern A: normal commands after activation

Once mise is active in your shell, moving into the directory can switch tools for you. The dev tools docs describe that behavior explicitly. (mise-en-place)

Pattern B: one-off execution

There’s also an execution mode that installs missing tool versions on demand when you run a command through mise. (mise-en-place)

Example:

mise exec node@24 -- node -v

That style is nice in CI, or anytime you want to be explicit.



Step 5: Put environment variables under version control (carefully)

The environments docs are direct about the goal: per-directory env vars, similar to direnv. (mise-en-place)

Add an [env] section:

# mise.toml
[env]
NODE_ENV = "development"
API_URL = "http://localhost:3000"

You can also unset an env var by setting it to false. (mise-en-place)

And there’s a CLI helper:

mise set API_URL=http://localhost:3000

That command edits mise.toml for you by default. (mise-en-place)

Loading an existing .env file

If your project already uses dotenv files, you don’t have to throw that away. You can load .env from the [env] section:

[env]
_.file = ".env"

That pattern is shown in guides and keeps compatibility with existing workflows. (Better Stack)

A quick reality check about secrets

My personal rule: do not casually commit secrets into mise.toml. Treat it like any other config file. Use a local override file, your secret manager, or a file that’s gitignored.

If you want the “team default” committed, keep it non-secret. If you need per-developer values, keep them local.



Step 6: Add tasks so everyone runs the same commands

This is where the video’s enthusiasm makes a lot of sense. The tasks doc calls out features that are usually painful when you roll your own:

  • dependency building in parallel by default
  • last-modified checks to avoid pointless rebuilds
  • mise watch for rebuild-on-change
  • tasks as real script files (so you get syntax highlighting) (mise-en-place)

Option A: tasks in mise.toml

[tasks.dev]
description = "Start the dev server"
run = "node server.js"

[tasks.test]
description = "Run tests"
run = "node --test"

[tasks.lint]
description = "Lint"
run = "eslint ."

Run them like this:

mise run dev
mise run test

The tasks doc also notes a shorter form: mise dev, as long as it doesn’t conflict with an existing mise subcommand. (mise-en-place)

Option B: “real files” task scripts

Create a directory like mise-tasks/ and drop executable scripts in it:

mkdir -p mise-tasks

mise-tasks/dev:

#!/usr/bin/env bash
#MISE description="Start the dev server"
node server.js

Make it executable:

chmod +x mise-tasks/dev

Then:

mise run dev

Same invocation, nicer authoring experience. (mise-en-place)



Step 7: Understand the trust prompt (this matters)

This is the part I wish every “smart shell tool” made obvious.

mise trust exists because some config features can be dangerous. The command marks a config file as trusted so it can be parsed with those features enabled. (mise-en-place)

There’s also a “paranoid” mode described in the docs, where trust is required more broadly. (mise-en-place)

My takeaway: treat it like your editor’s workspace trust.

  • Read the config first.
  • Trust it after you understand what it’s doing.
  • If you’re automating onboarding, document the trust step.

That small bit of friction is worth it.



Bonus: the “utilities like nix” angle

The YouTube snippet mentions “utilities like nix”, which is a fun rabbit hole if you’re in that world. (YouTube)

There’s a community plugin called mise-nix that installs packages via nix instead of the usual plugin flow. It’s explicitly aimed at Nix users who still want mise features, and it even supports pinning a nixpkgs ref. (GitHub)

Example from the plugin README:

mise plugin install https://github.com/chadac/mise-nix.git
mise install nix@python310
mise install nix@release-23.11/python310

I wouldn’t start here unless your team is already comfortable with Nix, but it’s nice evidence that mise can stretch without becoming a monolith.



A “full” example that looks like a real project

Here’s a compact setup that combines versions, env vars, and tasks:

# mise.toml
[tools]
node = "24"
terraform = "1"
aws-cli = "2"

[env]
TF_WORKSPACE = "development"
AWS_REGION = "us-west-2"
_.file = ".env"

[tasks.plan]
description = "Terraform plan"
run = """
terraform init
terraform workspace select $TF_WORKSPACE
terraform plan
"""

[tasks.deploy]
description = "Apply infra"
depends = ["plan"]
run = "terraform apply -auto-approve"

The official repo README includes a very similar combined example and suggests the same flow:

mise install
mise run deploy

(GitHub)

This is the “I get it now” moment. You can hand someone the repo and say: “Install mise, trust the config, run the tasks.” The rest becomes repeatable.



My honest thoughts after digging in

I like the idea more than I expected to.

  • The tool-version side is familiar. It feels like the natural evolution of “we all have 5 version managers installed”.
  • The env var side is where teams get messy fast, and having a consistent pattern helps.
  • The task runner is the surprise. The design choices feel opinionated in a good way, especially the “task scripts can be files” approach. (mise-en-place)

The main risk is social, not technical: adoption. Any time you introduce “one more tool”, someone will ask why you didn’t just keep using what you already have. The best answer is to show the repo getting simpler:

  • fewer setup docs
  • fewer local scripts
  • fewer “works on my machine” gaps

If you can make that improvement obvious, the tool sells itself.



If you try it, start small

If I were rolling this into an existing project, I’d do it in this order:

  1. Add mise.toml with tool versions.
  2. Get the team comfortable with mise install.
  3. Move one or two common tasks into mise run.
  4. Only then touch env var management.

That keeps the change easy to review and easy to back out, if you hate it.

And if you end up loving it, you’ll understand why a video would call it the “holy grail” with a straight face. (YouTube)







Last updated: 2026-02-22