## What is Mise? Mise, pronounced `meez`, is a polyglot tool version manager and development environment orchestrator. It aims to simplify the development workflow by providing a unified way to manage programming language runtimes, development tools, environment variables, and tasks across multiple projects. ## Key Benefits - Unified tool management - Project-specific versions - Fast and efficient - Cross-platform - Environment integration - Hierarchal configuration - Task runner - Secrets management - Backwards compatible ## Dev Tools Once [activated](https://mise.jdx.dev/getting-started.html#activate-mise), mise can automatically switch between different versions of tools based on the directory you're in. Replaces: - asdf - nvm - rbenv - pyenv - direnv - make - npm scripts ## Backends Use `mise registry` to see a list of all tools in the registry. - Core tools - Bun - Deno - Elixir - Erlang - Go - Java - Node.js - Python - Ruby - Rust - Swift - Zig - Backends - aqua - asdf - cargo - dotnet - gem - github - gitlab - go - http - npm - pipx - spm - ubi - vfox ## `mise use` `mise use` might be the only command you need to learn. It will do the following: - Install the tool's plugin if needed - Install the specified version - Set the version as active (i.e. update the `PATH`) - Update the current configuration file (`mise.toml` or `.tool-versions`) Examples: ```sh # Install the latest version of Ruby 3.4 mise use [email protected] # Install globally mise use -g [email protected] # Install all tools for a project based on the config mise install # Run one-off commands with specific tool mise x [email protected] -- ./myscript.py ``` ## Configuration Files Mise uses a sophisticated hierarchical configuration system. Configurations are merged, with more specific settings (closer to the current directory) overriding broader ones. **Other Supported Configuration Files:** - `.tool-versions`: Asdf's config file, supported by Mise for compatibility. Less flexible than `mise.toml`. - Idiomatic Version Files: Language-specific files like `.node-version, .ruby-version, .nvmrc, Gemfile, .python-version, .go-version`, etc. These allow projects to specify runtime versions without forcing Mise or Asdf. 1. Walks up the directory tree from the current location to the root. 2. Collects all config files found. 3. Merges them, with closer settings overriding broader ones. 4. Applies environment-specific configs (e.g., mise.development.toml if MISE_ENV=development). ## Environment Integration - **Automatic Activation (mise activate):** Hooks into the [[Shell]] prompt, updating PATH and environment variables when directories change. Recommended for interactive shells. Adds minimal latency (~10ms). - **On-Demand Execution (mise exec, mise x):** Runs commands with Mise's environment without persistent [[Shell]] activation. Useful for one-off commands or CI/CD. - **Shims (mise activate --shims):** Places small executables (symlinks to mise binary) in PATH that intercept commands and load the environment. Less feature-rich than PATH activation (e.g., env vars only available to Mise tools, most hooks won't trigger, which points to shim). Mise modifies your PATH to prioritize correct tool versions, ensuring direct execution of binaries (unlike asdf's shims, which add overhead). ## ENV Mise manages environment variables for different project directories, similar to direnv. - Defined in the `[env]` section of mise.toml. - Can be set/unset via CLI (`mise set`, `mise unset`). - Automatically sets variables in [[Shell]] sessions if Mise is activated. - Supports "lazy eval" to access environment variables produced by tools. - Environment variables can use templates and reference other environment variables. ### Secrets Because env vars in `mise.toml` can store sensitive information, mise has built-in support for reading encrypted secrets from files. Currently, this is done with a [sops](https://getsops.io/)implementation however other secret backends could be added in the future. ## Hooks You can have mise automatically execute scripts during a `mise activate` session. ### Examples ```toml [hooks] enter = "echo 'I entered the project'" leave = "echo 'I left the project'" preinstall = "echo 'I am about to install tools'" postinstall = "echo 'I just installed tools'" ``` You can also watch files, use [[Shell]] hooks and more. ## Tasks Mise includes a task runner to define and execute project-specific commands, replacing tools like make or npm scripts. - **TOML Tasks:** Defined in the [tasks] section of mise.toml. - **File Tasks:** Executable scripts in a designated directory (e.g., `mise-tasks/build`). These allow for full [[Shell]] script features. **Task Features:** - **Dependency Management:** Uses a directed acyclic graph (DAG) to ensure correct execution order. - `depends`: Prerequisites that must complete successfully. - `depends_post`: Run after the task completes (success or failure). - `wait_for`: Soft dependencies that run first if in the current execution, but don't fail if unavailable. - **Parallel Execution:** Runs tasks in parallel up to a configured job limit (default 4, configurable with --jobs or jobs setting). - **Source and Output Tracking:** Skips task execution if source files are older than output files, enabling incremental builds. - **File Watching (mise watch):** Automatically reruns tasks when their source files change. - **Task Grouping:** Semantic grouping using colons (e.g., test:unit). - **Wildcards:** Supports glob-style wildcards for running multiple tasks. - **Environment Variables:** Specific environment variables are passed to tasks (e.g., MISE_ORIGINAL_CWD, MISE_CONFIG_ROOT, MISE_TASK_NAME). - **Arguments/Flags:** Tasks can define arguments for validation, parsing, autocomplete, and documentation, accessible as usage\_ prefixed environment variables. ## Advanced ### [[Shell]] Scripts ```node #!/usr/bin/env -S mise x node@20 -- node // "env -S" allows multiple arguments in a shebang console.log(`Running node: ${process.version}`); ``` ### Cache ```sh mise cache clear ``` ### Auto Install ```toml [hooks] enter = "mise i -q" ``` ### Rails Example ```toml [env] # Project information PROJECT_NAME = "{{ config_root | basename }}" [tools] # Install Ruby with the specified version ruby = "{{ get_env(name='RUBY_VERSION', default='3.3.3') }}" [tasks."bundle:install"] description = "Install gem dependencies" run = "bundle install" [tasks.server] description = "Start the Rails server" alias = "s" run = "rails server" [tasks.test] description = "Run tests" alias = "t" run = "rails test" [tasks.lint] description = "Run lint using Rubocop" alias = "l" run = "rubocop" ``` ```toml # .mise.toml for an advanced Ruby on Rails application [settings] # Enable experimental features like `watch_files` hooks. # Note: Hooks are an experimental feature [3, 4]. experimental = true # Optional: Define the number of parallel jobs mise should use when running tasks. # The default is 4 [5-7]. # jobs = 8 [tools] # Define the Ruby version for this project. # You can specify an exact version (e.g., "3.4.4"), a major version (e.g., "3"), # or a stable release alias (e.g., "lts") [2, 8-11]. ruby = "3.4.4" # This will install Ruby 3.4.4 if not already present [12]. # Include Node.js if your Rails project uses it, for example, for asset compilation [2, 12]. node = "22" # This will install Node.js v22 if not already present [8]. # Install common Ruby CLI tools globally using the 'gem' backend. # This makes the 'rubocop' command available directly in your shell [13, 14]. "gem:rubocop" = "latest" # Install common Node.js CLI tools globally using the 'npm' backend. # This makes the 'prettier' command available directly in your shell [15-17]. "npm:prettier" = "latest" [env] # Add project-specific executable directories to the PATH environment variable. # This is crucial for ensuring Rails binstubs (e.g., `bin/rails`, `bin/bundle`) # and Node.js binaries (from `node_modules/.bin`) are directly accessible # without needing `mise exec` or `npx` prefixes [18-21]. # `{{config_root}}` ensures the path is relative to the directory containing this `mise.toml` file [19, 22]. _.path = ["{{config_root}}/bin", "{{config_root}}/node_modules/.bin"] # Set common environment variables for your Rails application. # `NODE_ENV` is set here, defaulting to 'development' if `MISE_ENV` is not explicitly set [2, 23-25]. NODE_ENV = "{{ env.MISE_ENV | default(value='development') }}" # Example of another custom environment variable. MY_RAILS_APP_SECRET = "your_project_specific_secret_key" [tasks] # Task to install Ruby gems and Node.js dependencies. # `sources` and `outputs` enable incremental execution, meaning the task only runs # if relevant source files (e.g., Gemfile, package.json) have changed, or if the # output directories (e.g., vendor/bundle, node_modules) are outdated [26, 27]. [tasks.install] description = "Install Ruby gems and Node.js dependencies for the project" run = [ "bundle install", # Installs Ruby gems defined in Gemfile. Binstubs are typically created in `bin/` [2]. "npm install" # Installs Node.js packages defined in package.json. ] sources = ["Gemfile", "Gemfile.lock", "package.json", "package-lock.json", "yarn.lock", "mise.toml"] outputs = ["vendor/bundle", "node_modules"] # Adjust paths if your `bundle install` or `npm install` outputs elsewhere. # Linting task for Ruby code using Rubocop. # The `rubocop` command is available because it was specified in the `[tools]` section [13]. [tasks.lint:ruby] description = "Run Rubocop for Ruby linting" run = "rubocop" # Linting/formatting task for other code files (e.g., JavaScript, CSS) using Prettier. # The `prettier` command is available from the `[tools]` section [16]. [tasks.lint:prettier] description = "Run Prettier for code formatting" run = "prettier --write ." # A grouped task to run all linting operations. # `depends` ensures both `lint:ruby` and `lint:prettier` tasks are executed before this task is considered complete. # They will run in parallel if possible, respecting the `jobs` setting [7, 28, 29]. [tasks.lint] description = "Run all linting tasks (Ruby and Prettier)" depends = ["lint:ruby", "lint:prettier"] # Task for running Rails database migrations. # `rails db:migrate` will use the Ruby version and binstubs configured by mise [30]. [tasks.db:migrate] description = "Run Rails database migrations" run = "rails db:migrate" # Task to start the Rails development server. # `bin/rails server` explicitly uses the project's binstub [18]. [tasks.start] description = "Start the Rails development server" run = "bin/rails server" # Task for running tests. [tasks.test] description = "Run project tests" run = "bin/rails test" [hooks] # This section defines hooks that are automatically executed by mise. # Note: These hooks, especially `watch_files`, are part of the experimental features, # hence `experimental = true` must be set in the `[settings]` section [3, 4]. # Use a `watch_files` hook to automatically run database migrations when `schema.rb` changes. # This is useful during development when new migrations are generated or applied [31, 32]. [[hooks.watch_files]] # Use `[[hooks.watch_files]]` to define multiple watch configurations in the same file [33]. patterns = ["db/schema.rb"] # Specifies the file to watch for changes [31]. # When `db/schema.rb` changes, execute the `db:migrate` task defined above [34, 35]. run = "mise run db:migrate" # The `MISE_WATCH_FILES_MODIFIED` environment variable will contain the list of changed files [31]. Explanation of Key Secti ```