Утилита mise (полное название MISE-EN-PLACE) настраивает необходимое для разработки окружение:
Для разработчика это глобальный набор инструментов (от языков программирования до мелких утилит) нужных версий.
Для проектов это аналогичный набор инструментов (специфичных для этого проекта версий, одинаковых у всех разработчиков и на CI) плюс конфигурация (переменные окружения/зашифрованные секреты для конкретного dev/staging/prod/… окружения плюс локальные отличия) плюс задачи (скрипты) для сборки/тестирования/деплоя/….
Есть множество других утилит решающих те же задачи, но mise сильно выделяется:
mise заменяет все остальные аналогичные утилиты т.к. содержит весь необходимый функционал.
То, что в других утилитах работало странно или не поддерживалось - в mise сделано правильно!
Безумная гибкость (дающая возможность внедрять mise постепенно):
… настройки (имена/количество/иерархия конфиг-файлов mise)
… стиля использования (от полного встраивания в шелл для максимального юзабилити до использования единственной необходимой команды
mise installилиmise run- для тех членов команды, которым не хочется разбираться с mise, но нужно работать с проектом использующим mise)… глубины внедрения в проект (нет необходимости обязательно использовать и установку инструментов и управление переменными окружения и задачи, а даже если использовать то нет необходимости обязательно управлять абсолютно всеми инструментами/переменными окружения/задачами именно через mise - можно переносить в конфиг mise всё это постепенно)
Фактически, все будущие аналогичные утилиты будут вынуждены равняться на mise, потому что mise задала новый стандарт "базовой функциональности" в этой области.
Разумеется, mise соответствует типовым ожиданиям от современной утилиты:
Написана на Rust. Т.е. для установки достаточно скачать один бинарник и работает очень быстро.
Работает на всех ОС (Linux/MacOS/Windows) и основных платформах (x64, arm).
Интегрируется (опционально) в любой шелл (bash, zsh, fish, powershell, nushell, xonsh, elvish).
Я использую mise примерно полтора года, постепенно перевожу на неё все свои проекты, и мне однозначно нравится результат! Дальше я опишу свои впечатления от использования mise, но, в общем и целом, всё необходимое есть в официальной доке.
Типовой сценарий использования mise
У вас установлена (один бинарник в PATH) и активирована (одна строка в
~/.bashrc) mise.Скачиваете (
git clone …) проект использующий mise.Заходите (
cd …) в каталог проекта, и в текущем шелле появляются переменные окружения с конфигурацией и расшифрованными секретами этого проекта (они пропадут, когда вы выйдете из каталога проекта).Запускаете
mise tasksчтобы увидеть список и описания всех задач проекта (сборка, тестирование, деплой, …) - нет необходимости искать эту информацию в README.Запускаете нужную задачу через
mise run …, причём с работающим--help, автодополнением имён, флагов и аргументов для всех задач. При этом будут автоматически установлены все необходимые этому проекту инструменты, причём тех же версий, какие используют все разработчики этого проекта.
Варианты интеграции в шелл/IDE
mise позволяет задать для проекта: инструменты, переменные окружения и задачи.
Задачи запускаются через mise run и всегда видят заданные инструменты и переменные окружения. Остаётся вопрос, как получить доступ к инструментам и переменным окружения проекта вне задач, т.е. в шелле/IDE/файловом менеджере вроде mc.
Любую команду можно запустить через mise exec -- команда, и тогда она тоже будет видеть заданные инструменты и переменные окружения.
Первый вариант интеграции: никакой интеграции не требуется, но запускать всё нужно исключительно через mise run и mise exec. Это удобный вариант для использования на CI, а так же если во время работы над проектом всё необходимое запускается либо через задачи mise либо через скрипты/Makefile в которых используется mise exec.
Если доступ к инструментам нужен напрямую, без mise exec, то возникает необходимость добавить путь к инструментам в $PATH (как минимум это актуально если используются глобально установленные инструменты).
Второй вариант интеграции: использование shims. В этом варианте в $PATH необходимо добавить один каталог ~/.local/share/mise/shims, который содержит симлинки для всех инструментов из всех конфигов mise (глобального и всех проектов) ведущие на саму mise. В результ��те, при запуске любого из этих инстументов будет запущена mise, которая обработает конфиги относящиеся к текущему каталогу/проекту, загрузит переменные окружения и запустит нужную версию инструмента. Задержка при таком запуске незначительная (порядка 30ms). Этот вариант рекомендуется использовать для запуска IDE и файловых менеджеров вроде mc, которые могут открывать разные проекты и запускать в них разные инструменты без mise exec.
Третий вариант интеграции: вызов eval "$(mise activate шелл)" при запуске шелла (т.е. добавление этой команды в ~/.bashrc и т.п.). В этом варианте будут установлены хуки в шелл, которые будут устанавливать $PATH и переменные окружения в зависимости от текущего проекта. Т.е. при cd в/из каталога проекта в $PATH будут добавляться/удаляться пути к индивидуальным инструментам (да, если у вас 100 инструментов, в то в $PATH будет 100 отдельных записей для них - и нет, тормозить это не будет) плюс перед выполнением каждой команды шелла будут добавляться/удаляться переменные окружения проекта. Это самый инвазивный вариант, но и самый удобный для интерактивной работы в шелле, потому что изменения конфигов mise сразу же отражаются в текущем шелле - в отличие от альтернатив вроде запуска шелла в каталоге проекта через mise exec -- bash или mise en, при которых PATH и переменные окружения задаются при запуске шелла и больше не обновляются.
Для некоторых IDE есть поддержка mise, позволяющая в т.ч. обеспечить доступ к переменным окружения.
Конфигурация
Конфиг mise п��шется в формате TOML, и обычно хватает двух файлов: ~/.config/mise/config.toml (с глобальными настройками и инструментами) и mise.toml в корне текущего проекта.
На первый взгляд может показаться, что если разработчик не сильно заинтересован в mise и вынужден ей пользоваться только потому, что mise используется в текущем проекте, то глобальный конфиг ему не нужен вообще. Но есть несколько нюансов, из-за которых глобальный конфиг всё-таки стоит создать почти всем:
Удобство. Для работы автодополнения в шелле флагов/аргументов самой
miseи флагов/аргументов задач проекта (mise run …) нужно установить дополнительную утилитуusage. Она не нужна конкретному проекту, поэтому вmise.tomlпроекта её никто не впишет, так что единственный способ её установить - добавить её в глобальный конфиг.Функциональность. Для поддержки автозапуска задач mise при изменении файлов проекта (через
mise watch …) тоже нужна дополнительная утилитаwatchexec. Та же история, что сusage.Производительность. Для установки инструментов через некоторые бэкенды доступны альтернативные, более эффективные альтернативы. Например использование bun или pnpm вместо npm для бэкенда npm. Это имеет смысл настроить именно в глобальном конфиге.
Безопасность. В mise есть поддержка "параноидального" режима. Поскольку конфиги mise могут приводить к выполнению любых команд и изменять переменные окружения при входе в каталог проекта, и при этом они скачиваются/обновляются из чужих репозиториев, то есть смысл их просматривать перед использованием. Параноидальный режим обеспечивает более строгую защиту, и для его включения и настройки тоже нужно использовать глобальный конфиг.
В результате, минимальный глобальный конфиг эффективного параноика :) выглядит примерно так:
[settings] disable_default_registry = true paranoid = true # В ~/proj/ только личные проекты, рабочие и форки чужих в других каталогах. trusted_config_paths = ["~/proj/"] [settings.npm] package_manager = "pnpm" [tools] # Нужна для поддержки автокомлита в шелле для mise и mise tasks проектов. usage = "latest" # Нужна для поддержки `mise watch`. watchexec = "latest" # Нужна для settings.npm.package_manager. pnpm = "latest" # Ускоряет установку для бэкенда "cargo:". cargo-binstall = "latest"
Файл mise.toml в корне проекта - это далеко не единственный вариант имени и расположения конфига mise. Это может показаться спорным решением, но mise поддерживает больше десятка базовых вариантов - разное расположение (в корне, в подкаталогах mise/, .config/, .config/mise/), разное именование (имена могут начинаться и на mise и на .mise), разная структура (один файл или каталог с файлами). Добавим локальные версии этих конфиг-файлов (заканчивающиеся на .local.toml, которые должны быть указаны в .gitignore). Плюс добавим версии файлов для разных окружений (dev/staging/prod). В результате легко получить с полсотни возможных путей к конфигам mise. Плюс рекурсивная подгрузка конфигов из вышестоящих каталогов… Тем не менее, для всех этих вариантов чётко определены приоритеты и правила объединения настроек, так что если не пытаться специально создать максимальный бардак, и придерживаться в рамках проекта какого-то одного стиля, то никаких реальных проблем эта гибкость не создаст. Команда mise config покажет, какие конфиги и в каком порядке загружаются для текущего каталога.
Конфиги mise можно редактировать двумя способами: либо как обычный файл, либо через соответствующие команды mise (mise edit, mise use …, mise settings …, etc.). Я рекомендую использовать какой-то один из этих двух подходов, потому что редактирование командами может приводить к удалению вручную добавленных комментариев и перемещению записей в конфиге.
Инструменты
mise возвращает контроль над установленными глобально (для текущего пользователя, а не конкретного проекта) инструментами. В глобальном конфиге mise можно добавить комментарии, помогающие вспомнить зачем был нужен когда-то установленный инструмент. mise даёт возможность одной командой обновить все инструменты, узнать какие версии каждого инструмента установлены и удалить уже не нужные (отсутствующие в конфиге) инструменты/версии. Переход на mise позволил мне капитально почистить свои ~/.local/bin/ и ~/go/bin/ от непонятных бинарников, установленных много лет назад.
Что можно установить через mise? Практически всё! Сама mise реализует установку языков программирования (Go, Java, NodeJS, Python, …), а всё остальное устанавливается через кучу разных "бэкендов" реализующих совместимость с разными источниками приложений. Например:
бэкенд github позволяет установить любой бинарник выложеный в GitHub Releases
бэкенд go позволяет установить любое приложение поддерживающее установку через
go installбэкенды aqua, asdf, vfox позволяют установить любое приложение которое умеют устанавливать эти утилиты
бэкенды npm, pipx, gem позволяют установить пакеты из соответствующих репозиториев
… и это далеко не полный список бэкендов
А что делать, если нужный инструмент всё-таки отсутствует? Написать для установки этого инструмента свой плагин для vfox (на lua) или asdf (на bash), после чего его сможет установить и mise через соответствующий бэкенд.
В mise есть собственный реестр инструментов, который позволяет указать инструмент без бэкенда, т.е. сделать mise install rg вместо mise install aqua:BurntSushi/ripgrep или mise install cargo:ripgrep или mise install github:BurntSushi/ripgrep. В этом реестре сейчас под 1000 инструментов, но это не значит, что через mise можно установить только эту 1000 - просто для установки остальных нужно явно задавать backend и полное имя инструмента.
Так же через mise довольно удобно пробовать новые инструменты. Например, сегодня в новостях прочитал про утилиту llm-checker: открыл гитхаб, увидел что она написана на JS, и этого хватило чтобы запустить её через mise exec npm:llm-checker -- llm-checker -h. При первом запуске она скачалась и установилась, но поскольку ни в какие конфиги mise я её не добавил, то когда в будущем будет запущен mise prune она будет удалена.
mise позволяет одновременно установить кучу разных версий одного инструмента. Если у этих версий разные названия бинарников (напр. python3.12) то они будут доступны все одновременно, а если бинарник называется одинаково то можно выбрать какую версию использовать запустив команду через mise exec TOOL@VERSION -- команда. А при запуске задач mise можно прямо в конфиге mise для конкретной задачи задать какие версии каких инструментов должны быть видны в этой задаче (например, чтобы прогонять тесты на предыдущих версиях языка).
Есть два способа задать нужную проекту версию инструмента: либо указать её непосредственно в конфиге mise, либо использовать для этого отдельный lockfile. На мой взгляд, в конфиге mise лучше указывать принципиально поддерживаемое проектом подмножество версий - обычно либо "latest" если требуется поддержка любой новой версии, либо префикс версии вроде "1.2" если поддерживаются все "1.2.x - это заметно упростит регулярное обновление инструментов через mise up и явно покажет, что поддержки других версий нет. А lockfile при этом будет содержать конкретную версию "1.2.3", заданную последним вызовом mise up, что обеспечит использование именно этой версии всеми разработчиками и на CI. Для использования lockfile нужно добавить в mise.toml в разделе [settings] опцию lockfile = true, плюс вручную создать пустой lockfile: touch mise.lock - и я рекомендую делать это во всех проектах.
Ещё полезные нюансы/фичи:
Нужную версию инструмента лучше всегда указывать без префикса "v".
Если одна версия инструмента нужна разным проектам то она устанавливается однократно.
Есть возможность использовать локально модифицированную версию инструме��та вместо стандартной.
При установке инструмента проверяются подписи/контрольные суммы (если это поддерживается бэкендом, через который устанавливается данный инструмент).
Многие инструменты можно установить через несколько разных бэкендов, поэтому лучше придерживаться какого-то общего приоритета при выборе бэкенда, чтобы не создавать лишний бардак и не устанавливать одну и ту же версию одного инструмента несколько раз.
(Актуально на 2026-02-22, надеюсь это поправят в будущем.) При использовании lockfile, если не запускать вручную
mise lockпосле каждого добавления/обновления инструментов, этот lockfile может внезапно изменяться во времяmise install(из-за того, что нужный инструмент не был ранее установлен локально или установка выполняется на другой ОС). Это может создавать проблемы на CI (если там проверяется что рабочий каталог git не dirty) плюс замусоривать не связанные с обновлением mise PR-ы других членов команды. На CI это проще всего решить добавивgit reset --hardпослеmise install.
Переменные окружения и секреты
Адекватный, интуитивно ожидаемый приоритет установки значений переменных.
Можно задавать значения новых переменных используя значения ранее заданных переменных.
Можно задавать значения переменных используя вывод внешней команды.
Загрузка переменных из файлов в формате dotenv.
Загрузка переменных экспортируемых sh-скриптом.
Полноценный язык шаблонов позволяет гибко трансформировать значения переменных.
Отложенная установка переменных позволяет переопределять в
mise.local.tomlпромежуточные переменные (напр.$PORT), и использовать переопределённые значения при установке "отложенных" переменных вmise.toml(напр.$URLсодержащая внутри$PORT).Установка переменных для секретов, зашифрованных как непосредственно в конфиге mise (утилитой age), так и в удалённых сервисах (Vault, AWS KMS/SM, Azure, GCP, 1Password, …).
Задачи
Задачи можно задавать прямо в TOML конфиге mise (удобно для однострочных команд, приемлемо для двух-трёх строчных) и в отдельных скриптах (для более многострочных задач). Причём даже внутри конфига задача не обязательно должна быть шелл-командой, это вполне может быть код на python и т.п.
Если в проекте уже есть что-то вроде каталога со скриптами для типовых задач (напр. ./scripts/build, ./scripts/test, …), то mise сможет подхватить эти скрипты как свои задачи. А для того, чтобы в этих задачах воспользоваться дополнительными фичами mise (задать описание, alias, переменные окружения, зависимости, версии нужных инструментов, автодополнение флагов/аргументов) достаточно добавить в начале скрипта комментарии #MISE … и #USAGE ….
Для новых задач, не важно они в конфиге mise или отдельных скриптах, помимо автодополнения флагов/аргументов при запуске, флаги/аргументы будут автоматически разобраны и их значения будут доступны в переменных окружения $usage_… - это упрощает реализацию задач.
Для максимальной ленивости удобно добавить в шелл alias mr='mise run' плюс самую часто используемую задачу проекта указать как "default", тогда она будет запускаться по mr.
Ещё полезные фичи:
Просмотр названий и описаний всех задач.
Флаги и аргументы для задач с поддержкой
--helpи автодополнения в шелле.Настройка версий инструментов, переменных окружения и рабочего каталога для отдельных задач.
Зависимости между задачами.
Параллельное выполнение задач.
Пропуск задачи если конкретные файлы не изменились с предыдущего запуска этой задачи.
Автоматический запуск задач (через
mise watch) при изменении конкретных файлов.
Разное
mise версионируется по CalVer, и релизы очень частые (почти каждый день). Обычно они совместимы и острой необходимости обновляться нет, но у меня уже выработалась привычка каждый день плюс к обновлению ОС запускать mise self-update для обновления mise плюс mise up для обновления всех установленных через mise глобальных утилит. В случае необходимости форсировать обновление mise у всех разработчиков проекта в конфиге mise можно указать минимально необходимую версию mise.
Есть поддержка монорепо.
Ваша команда может даже не подозревать, что вы используете mise при работе с проектом. Для этого достаточно написать личный конфиг для проекта в mise.local.toml и добавить игнорирование этого файла в ~/.gitconfig.
Для отладки проблем с mise запустите mise doctor.
Примеры mise.toml для проектов разных типов: утилита на Go, библиотека на Go, плагин для KDE Plasma на JavaScript, плагин для Neovim на Lua.
