Eine Einführung in mise, den Versionsmanager für mehrere Sprachen
Erfahren Sie, wie mise Node- und Python-Versionen pro Projekt verwaltet, vorhandene Versionsdateien nutzt, Tools fixiert und Builds lokal sowie in CI ausführt.
mise ist ein einzelnes Kommandozeilenwerkzeug, das Versionen von Node, Python, Ruby und anderen Runtimes pro Verzeichnis installiert und umschaltet. Die Versionen liest es aus einer mise.toml-Datei im Projektstammverzeichnis.
Wenn Ihr Repo ein Vite-Frontend und ein Python-Skript enthält, das vor dem Build Inhalte generiert, betreiben Sie vermutlich nvm und pyenv parallel und hoffen, dass die Shell jedes Teammitglieds mit der CI übereinstimmt. Meist tut das eine davon nicht.
Einen direkten Vergleich von mise, nvm, pyenv, rustup und SDKMAN! finden Sie in 5 Version Managers Every Developer Should Know. Dieser Artikel verzichtet auf eine Feature-Liste. Stattdessen nimmt er ein einzelnes Repo und verfolgt es durch cd, vorhandene .nvmrc-Dateien, den ersten Clone eines Teammitglieds, die CI, einen Build-Task über zwei Runtimes und Umgebungsvariablen.
Das Wichtigste in Kürze
- Mit aktivierter Shell-Integration landen beim Betreten eines Verzeichnisses mit
mise.tomldie dort festgelegten Runtimes im PATH. Beim Verlassen werden die vorherigen Versionen wiederhergestellt. - mise ignoriert
.nvmrcund.python-version, sofern Sie diese nicht pro Tool über die Einstellungidiomatic_version_file_enable_toolsaktivieren. mise runlädt die Tools und Umgebungsvariablen des Projekts selbst und installiert fehlende Tools standardmäßig nach. Dadurch funktioniert es in der CI auch ohne Shell-Aktivierung.jdx/mise-action@v4installiert mise und die Tools ausmise.toml. Ist einemise.lockeingecheckt, erfolgt die Installation mit--locked.- Die
[env]-Tabelle ist Klartext, der committet wird. Sie ist für Konfiguration gedacht, nicht für Secrets.
Das Projekt: Ein Vite-Frontend mit Python-Build-Schritt
Das Beispiel-Repo docs-preview umfasst zwei Runtimes, eine Konfigurationsdatei und einen Workflow:
docs-preview/
├── content/*.md
├── scripts/build_content.py
├── src/
├── package.json # vite in devDependencies
├── mise.toml
└── .github/workflows/build.yml
Das Python-Skript verwendet ausschließlich die Standardbibliothek. Es wandelt die Markdown-Dateien in JSON um, das das Frontend importiert:
# scripts/build_content.py
import json, os, pathlib
src = pathlib.Path(os.environ.get("CONTENT_DIR", "content"))
out = pathlib.Path("src/generated/content.json")
out.parent.mkdir(parents=True, exist_ok=True)
items = [{"slug": p.stem, "body": p.read_text(encoding="utf-8")}
for p in sorted(src.glob("*.md"))]
out.write_text(json.dumps(items, indent=2), encoding="utf-8")
print(f"wrote {len(items)} items to {out}")
Dies ist die vollständige mise.toml. Die folgenden Abschnitte beziehen sich darauf:
[tools]
node = "24"
python = "3.14"
[settings]
lockfile = true
[env]
CONTENT_DIR = "content"
VITE_SITE_NAME = "Docs Preview"
[tasks.install]
description = "Install JS dependencies"
run = "npm ci"
[tasks."build:content"]
description = "Convert content files to JSON for the frontend"
run = "python scripts/build_content.py"
[tasks.build]
description = "Generate content, then build the Vite app"
depends = ["install", "build:content"]
run = "npx vite build"
Die [tools]-Tabelle verwendet Versionspräfixe (Node 24 LTS, Python 3.14). Das weiter unten beschriebene Lockfile hält die exakten Patch-Versionen fest, zu denen diese aufgelöst werden.
Was beim Betreten und Verlassen eines Verzeichnisses passiert
Ist mise aktiviert, landen beim Betreten eines Verzeichnisses mit mise.toml die dort festgelegten Runtimes in Ihrem PATH. Beim Verlassen werden die zuvor aktiven Versionen wiederhergestellt. Sobald mise activate in Ihrer Shell-Startdatei steht, tauscht mise bei jedem Verzeichniswechsel Tools und Umgebungsvariablen aus.
cd ~
node --version # whatever your system or nvm provides
cd ~/code/docs-preview
node --version # v24.x from mise.toml
python3 --version # Python 3.14.x
echo "$CONTENT_DIR" # content
Wann mise die Versionen umschaltet, hängt von der Shell ab. Laut der Shims-Dokumentation schalten bash, zsh, fish und xonsh um, sobald Sie cd ausführen. Andere Shells warten, bis der nächste Prompt erscheint.
Wenn eine festgelegte Version noch nicht installiert ist
Führen Sie auf einem frischen Rechner mise install im Projektverzeichnis aus. Das ist die explizite, vorhersehbare Lösung. Tasks nehmen Ihnen das ebenfalls ab: mise-Tasks laufen mit den Tools und Umgebungsvariablen des Projekts, und die standardmäßig aktive Einstellung auto_install installiert beim Aufruf von mise run alle fehlenden konfigurierten Tools. Bei Python ist Vorsicht geboten, wenn Sie sich auf Shims verlassen. Die Settings-Referenz erläutert, dass ein Shim, der keine von mise verwaltete Version auflösen kann (etwa bei deaktiviertem Auto-Install), auf das erste gleichnamige Programm an anderer Stelle im PATH zurückfällt. Bei einem Tool, das auch das Betriebssystem mitbringt, wie python3, bedeutet das: Ihre festgelegte Version wird nie ausgeführt, und Sie erhalten keinen Fehler.
Um eine andere Version nur in einem einzelnen Terminal festzulegen, verwenden Sie mise shell node@<version>. Dafür ist eine Shell erforderlich, in der mise bereits aktiviert ist.
Vorhandene .nvmrc- und .python-version-Dateien
mise liest .nvmrc oder .python-version nur, wenn Sie dies pro Tool über idiomatic_version_file_enable_tools aktivieren. Die mise-FAQ bestätigt, dass diese sogenannten idiomatischen Versionsdateien standardmäßig deaktiviert sind. Dieser Standard wurde mit mise 2025.10.0 eingeführt. So aktivieren Sie sie:
[settings]
idiomatic_version_file_enable_tools = ["node", "python"]
Die Konfigurationsdokumentation führt package.json unter den Dateien auf, die mise für node liest. Wenn Sie node aktivieren, kann also auch diese Datei berücksichtigt werden. Um eine einzelne Datei auszuschließen, fügen Sie der Einstellung idiomatic_version_file_disable_files ein tool:filename-Paar wie node:package.json hinzu.
Sobald mise.toml beide Runtimes festlegt, behalten Sie .nvmrc nur für Teammitglieder bei, die noch nvm nutzen, und achten Sie darauf, dass beide Dateien übereinstimmen. Wenn Sie auffrischen möchten, wie nvm mit dieser Datei umgeht, lesen Sie die Anleitungen zum Wechseln von Node-Versionen mit nvm unter macOS, Linux und Windows.
Teammitglieder und CI
Ein Laptop und ein CI-Runner lesen dieselbe mise.toml, bringen die Tools aber auf unterschiedliche Weise in den PATH:
| Laptop | GitHub Actions | |
|---|---|---|
| Tools im PATH | Aktivierungs-Hook in der Shell | jdx/mise-action installiert mise und die festgelegten Tools |
| Versionsquelle | mise.toml + mise.lock | Dieselben Dateien |
| Build-Befehl | mise run build | mise run build |
Der erste Clone eines Teammitglieds:
- mise installieren:
curl https://mise.run | sh eval "$(~/.local/bin/mise activate zsh)"(oder die entsprechende Zeile für Ihre Shell) in die rc-Datei Ihrer Shell eintragen.mise.tomlprüfen, dannmise installausführen.mise run buildausführen.
Das Vertrauensmodell von mise verdient Aufmerksamkeit, da Konfigurationsdateien Code ausführen können. Laut dem Getting-started-Guide vertraut außerhalb der CI und des Paranoid-Modus jeder Befehl, der auf das Projekt wirkt – etwa mise install, mise exec oder mise run –, der aktiven Konfiguration automatisch. Prüfen Sie daher mise.toml, bevor Sie einen solchen Befehl ausführen, und verwenden Sie mise trust, wenn Sie einer Konfiguration explizit vertrauen möchten.
Exakte Versionen festschreiben. Das Lockfile mise.lock wird durch mise lock oder durch die oben gezeigte Einstellung lockfile = true erzeugt. Committen Sie es. Mit mise install --locked führt ein fehlender Lock-Eintrag zu einem Fehler, sodass mise nie stillschweigend eine neue Version wählt.
CI-Workflow:
# .github/workflows/build.yml
name: build
on: [push, pull_request]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: jdx/mise-action@v4
- run: mise run build
Der mise-action-Schritt installiert mise und die Tools aus mise.toml, sodass der Workflow dieselben Versionen verwendet wie die Entwickler lokal. Standardmäßig führt er mise install aus (install: true) und cacht die Tools (cache: true). Ist mise.lock vorhanden, installiert er mit --locked. Außerdem übergibt er automatisch ${{ github.token }}. Auf Laptops hilft das Setzen von GITHUB_TOKEN oder MISE_GITHUB_TOKEN, wenn Installationen an Rate Limits stoßen, wie auf der Seite zu GitHub-Tokens beschrieben.
Wenn etwas nicht funktioniert, grenzen drei Befehle das Problem ein:
| Symptom | Befehl |
|---|---|
| Aktivierung oder Installation wirkt fehlerhaft | mise doctor |
| Offenbar greift die falsche Konfigurationsdatei | mise config ls |
| Falsche Version ausgewählt | mise ls --current |
Ein echter Task: mise run build über zwei Runtimes
Ein in mise.toml definierter Task läuft mit den festgelegten Tools und [env]-Variablen des Projekts, die bereits angewendet sind. Dadurch verwendet mise run build auf dem Laptop und in der CI dasselbe Node und Python – auch ohne Shell-Aktivierung.
Der Schlüssel depends sorgt dafür, dass build wartet, bis alle aufgeführten Tasks abgeschlossen sind. So hat der Python-Schritt src/generated/content.json geschrieben, bevor Vite die Datei liest. Die aufgeführten Tasks können nebenläufig ausgeführt werden. Laut Task-Dokumentation dürfen Voraussetzungen parallel laufen, und ihre Reihenfolge in depends legt keine Abfolge fest. Hier ist das unbedenklich, denn npm ci schreibt node_modules und das Python-Skript schreibt src/generated – keiner der beiden Schritte berührt die Ausgabe des anderen. Sollte ein Schritt künftig die Ausgabe des anderen verarbeiten, machen Sie ihn direkt von diesem Schritt abhängig.
mise tasks # lists install, build:content, build
mise run build # npm ci + Python step, then vite build
Der Guide zum Ausführen von Tasks legt das Standardlimit auf acht parallele Jobs fest.
Projektspezifische Umgebungsvariablen mit mise
Werte in der [env]-Tabelle stehen im Klartext in einer committeten Datei. mise env ist Konfigurationsmanagement, kein Secret-Management. Im Beispiel liest das Python-Skript CONTENT_DIR über os.environ, und das Frontend liest import.meta.env.VITE_SITE_NAME.
Das Präfix VITE_ macht das Risiko von Klartextwerten in [env] konkret. Die Vite-Dokumentation zu Umgebungsvariablen erläutert, dass jede Variable mit dem Präfix VITE_ im Client-Bundle landet, wobei ihr Wert zur Build-Zeit in den Code geschrieben wird. Jeder VITE_-Wert in mise.toml ist öffentlich, sobald die Website ausgeliefert wird.
Eine fehlende Build-Time-Variable lässt den Build nicht scheitern. Stattdessen erhalten Sie ein Bundle, das die falsche URL aufruft. Session Replay kann dies aus Nutzersicht sichtbar machen: Sie sehen, wie Requests an eine undefined-Basis-URL gehen, und können das Problem dann auf die Umgebung zurückführen, in der der Build lief.
Wann lohnt sich mise?
Benötigt ein Projekt nur Node, erledigen nvm und eine .nvmrc die Aufgabe bereits, und mise ist optional. Die nvm-Anleitungen decken dieses Setup gut ab. mise lohnt sich, wenn ein Repository zwei oder mehr Runtimes festlegt und die CI mit jedem Laptop übereinstimmen muss. Um es in einem bestehenden Repo auszuprobieren, fügen Sie eine mise.toml mit [tools]-Pins hinzu, führen mise lock aus, committen beide Dateien und ändern Ihren CI-Build-Schritt auf mise run build.
FAQs
Wo sollte ich Secrets ablegen, wenn mise.toml committet wird?
Legen Sie Secrets in einer per .gitignore ausgeschlossenen mise.local.toml ab oder deklarieren Sie sie in mise.toml mit required = true. Dann prüft mise, ob die Variable gesetzt ist, ohne einen Wert zu speichern. Mit redact = true werden Werte in erfasster Task-Ausgabe maskiert, mise env gibt sie jedoch weiterhin im Klartext aus. Für Secrets, die committet werden müssen, kann mise mit age verschlüsselte SOPS-Dateien (ein experimentelles Feature) für mise exec, Tasks und die Shell-Aktivierung entschlüsseln.
Liest mise asdf-Dateien vom Typ .tool-versions?
Ja. Anders als .nvmrc liest mise .tool-versions ohne zusätzliche Einstellungen. Unter Unix kann es außerdem asdf-Shell-Plugins ausführen, allerdings ist nicht garantiert, dass jeder asdf-Befehl und jedes Plugin funktioniert. Deklarieren mise.toml und .tool-versions im selben Verzeichnis dasselbe Tool, hat mise.toml Vorrang. Die mise-Dokumentation rät davon ab, Installationsverzeichnisse zwischen asdf und mise zu teilen. Führen Sie daher nach dem Umstieg mise install aus.
Warum verwenden mein Editor oder mein Skript eine andere Node-Version als mein Terminal?
Editoren, Git-Hooks und Scheduler laden Ihre interaktive rc-Datei oft nicht, sodass der Aktivierungs-Hook von mise nie ausgeführt wird. Um das zu beheben, fügen Sie mise activate zsh --shims (oder die entsprechende Zeile für Ihre Shell) in ein Login-Profil ein, das Ihr Editor liest, etwa ~/.zprofile, und belassen das normale mise activate in ~/.zshrc. Für Skripte verwenden Sie stattdessen mise exec -- command oder mise run. Im Shim-Modus entfallen einige Aktivierungsfunktionen, etwa die meisten Hooks.