Einleitung
Für die meisten Entwickler weckt der Begriff Onboarding schlechte Erinnerungen und Frustration: veraltete Anleitungen im Wiki, fehlende Abhängigkeiten, undokumentierte Besonderheiten, inkompatible Tool-Versionen und das berüchtigte „works on my machine“. Ganz gleich, ob neue Mitarbeiter einem Team beitreten oder erfahrene Entwickler zwischen Projekten wechseln – Der Einstieg in ein neues Projekt fühlt sich wie eine Schnitzeljagd an, der Stunden oder sogar Tage kostet, bevor produktive Arbeit möglich ist.
Erfahrungsberichte und Studien stützen dieses Gefühl. Teams unterschätzen dabei oft, wie viel Produktivität, Motivation und Entwicklungsgeschwindigkeit durch diese Inkonsistenzen verloren gehen.
Genau hier kommen reproduzierbare Entwicklungsumgebungen ins Spiel. Sie ermöglichen Toolchains, Abhängigkeiten und Systemkonfigurationen zusammen mit dem Quellcode deklarativ zu verwalten und anschließend zuverlässig überall zu reproduzieren – auf lokalen Laptops, in CI-Pipelines oder innerhalb von Containern – ohne Drift und ohne manuelles Nachjustieren.
Dieser Artikel stellt verschiedene Ansätze und Werkzeuge vor – SDKMAN!, asdf, mise, und Nix mit Devbox – und zeigt, wie sie den Onboarding-Schmerz deutlich reduzieren können und wo sie sich unterscheiden.
SDKMAN! – für JVM Projekte
SDKMAN!1 ist ein Kommandozeilen Tool, dass einem ermöglicht alle notwendigen Tools für die Java-Entwicklung wie Build-Tools oder auch JDKs selber zu installieren und dabei auch verschiedene Versionen von diesen zu pflegen. Egal ob man zwischen Java JDK Distributionen wechseln möchte oder Tools wie Maven oder Gradle zum Bauen benötigt, mit SDKMAN! kann man mit einfachen Befehlen diese installieren bzw. zwischen Versionen hin und herwechseln.
sdk list java # Listet alle verfügbaren JDKs auf
sdk install java 25.0.1-tem # Installiert Temurin JDK 25
sdk default java 25.0.1-tem # Setzt Temurin JDK 25 als Default
sdk use java 21.0.8-tem # Wechselt temporär auf Temurin JDK 21
sdk install maven 3.9.12. # Installiert Maven
Der Fokus liegt dabei klar auf dem Java Ökosystem und ist damit nicht ein genereller Paket-Manager. Es unterstützt dafür eine große Bandbreite an Tools, die typischerweise im Java Umfeld genutzt werden, egal ob Build Tools wie maven oder Gradle, Sprach-SDKs wie Groovy oder Kotlin oder auch Analyse-Tools wie Java Mission Control oder VisualVM können mit SDKMAN! verwaltet werden.
Die notwendigen Tools und JDKs lassen sich auch für ein Projekt zusammen mit den Quellcode verwalten. Dafür bietet SDKMAN! die Datei .sdkmanrc an, die mit in das Git Repository eingecheckt werden kann. Der Inhalt ist eine Auflistung der Tools/SDKs und deren zugehörigen Versionen für das Projekt
java=25.0.1-tem
maven=3.9.12
Auf einer anderen Maschine lässt sich dann auf einen Schlag alle notwendigen Tools installieren und auch wechseln.
sdk env install # installiert alle Tools, die in .sdkmanrc definiert sind
sdk env # wechselt auf die Versionen aus der .sdkmanrc
Damit lässt sich ein Teil der Entwicklungsumgebung einfach reproduzieren. Eine netter Nebeneffekt ist, dass IDEs wie IntelliJ ebenfalls diese Datei erkennt und das JDK dementsprechend beim Öffnen des Projekts setzt. SDKMAN! unterstützt dabei Linux, MacOS und auch Windows (via WSL oder Git Bash) und ist damit für reine Java Projekte eine gute Wahl.
asdf – Wenn es mal nicht Java ist
Für andere Sprachen gibt es ähnliche Tools wie SDKMAN!, z.B. rbenv für Ruby oder nvm für Nodejs. Einen generischen Ansatz verfolgt das Tool asdf2. Anstatt sich auf ein Ökosystem zu konzentrieren, schafft es eine Basis um beliebige Tools und Software zu verwalten. Um dies zu erreichen benutzt es das Konzept der sogenannten “Plugins”. Jedes Plugin ist dabei für ein bestimmtes Tool verantwortlich. Im Kern ist ein Plugin ein Git Repository, das einer bestimmten Struktur folgt und Bash Skripte zur Verfügung stellt, mit der für ein Tool Versionen aufgelistet werden können oder auch diese Tools installiert werden können. Diese Plugins können installiert werden und danach genutzt werden um die verschiedensten Tools zu verwalten. Als Beispiel schauen wir uns die Nutzung von Node an:
asdf plugin add nodejs https://github.com/asdf-vm/asdf-nodejs.git
asdf list all nodejs
asdf install nodejs 25.4.0
Wie man sieht ist ein Plugin nichts weiteres als ein Git-Repository mit einer bestimmten Ordnerstruktur. In dem Repository existieren Skripte, die sich dann um die konkreten Befehle kümmern und auch die Installation durchführen. Beispielhaft sieht ein Git-Repository eines Plugins wie folgt aus:
bin/
├── list-all
├── download
├── install
├── ...
├── uninstall
└── ...
Es gibt für alle möglichen Tools bereits Plugins, aber durch diesen Ansatz ist es relativ einfach eigene Plugins zu schreiben. Dieser Vorteil ist auch gleichzeitig ein Nachteil. Man muss bei der Installation eines Plugins dem Besitzer des Repositories vertrauen, da auf dem Rechner beliebige Befehle damit ausgeführt werden könnten. Es gibt an sich keine kuratierten Plugins der asdf Entwickler. Die meisten Plugins kommen aus der asdf-community, aber viele werden auch außerhalb der Community gepflegt. Viele Plugins sind auch veraltet oder bereits archiviert.
Neben den Themen Vertrauen und Sicherheit wird auch regelmäßig über die Performance diskutiert. Auslöser dafür ist die Designentscheidung von asdf, sogenannte Shims einzusetzen. Für jedes installierte Tool erzeugt asdf einen Shim, der den Toolaufruf abfängt und gezielt an die aktuell ausgewählte Version weiterleitet. Auf diese Weise behält asdf die volle Kontrolle darüber, wo es Tools installiert und welche Version bei einem konkreten Aufruf zum Einsatz kommt. Es hat damit aber auch Performanceeinbußen bei jedem einzelnen Aufruf, die vielleicht im Einzelnen nicht ins Gewicht fallen, aber bei vielen Aufrufen bemerkbar sind. Zusätzlich bietet asdf auch keinen Windows-Support an.
Ähnlich dem Ansatz von SDKMAN! mit der .sdkmanrc Datei, gibt es bei asdf die .tools-version Datei. Der Aufbau ist dabei ähnlich.
nodejs 24.13.0
Die .tool-Version Datei muss dabei nicht direkt in dem Ordner der Ausführung liegen, sie kann auch in einem übergeordneten Ordner liegen. Damit kann man Versionen für mehrere Projekte verwalten.
Für diejenigen, die mit den Nachteilen nicht leben können aber trotzdem diese Vielfalt und Flexibilität nutzen möchten, können möglicherweise bei dem nächsten Tool fündig werden.
Mise – Das bessere asdf?
Mise3 verfolgt einen ähnlichen Ansatz wie asdf und hat am Anfang auch das Plugin System von asdf genutzt. Aber genau wegen den Sicherheitsproblemen unterstützt mise auch andere sogenannte Backends, die sich um die Installation verschiedener Tools kümmern. Darunter gehören:
- github – installiert Releases direkt von github Repositories
- cargo – installiert tools via
cargo - go – installiert tools via
go install
Ein Backend kann bei der Installation eines Tools direkt mit angegeben werden
mise use -g github:BurntSushi/ripgrep # github backend
mise use -g cargo:eza # cargo backend
mise use -g go:github.com/DarthSim/hivemind # go backend
Darüber hinaus kommt Mise mit ein einigen Core Plugins daher, für die nicht explizit ein Backend angegeben werden muss, um verschiedene Versionen zu verwalten. Dazu gehören u.a.
- Java
- Go
- Node.js
- Rust
Die Installation verschiedener Versionen dieser Tools funktioniert gleich wie die Installation mti einem spezifischen Backend.
mise use -g java@openjdk-21
mise use -g go@1.21
mise use -g node@20
mise use -g rust
Was mise von asdf abhebt neben der größeren Auswahl an Backends und Tools, ist die Möglichkeit weitere projektspezifische Eigenschaften zu verwalten, wie z.B. projektspezifische Umgebungsvariablen oder Tasks.
Neben der Nutzung einer .tool-versions Datei gleich wie asdf, bietet es auch eine eigene Konfigurationsdatei an, die man mit dem Projekt verwalten kann. Eine Beispielkonfiguration sieht wie folgt aus:
[tools]
node = '24'
[env]
MY_VAR = '123'
[tasks.hello]
run = "echo hello world"
Diese können dann direkt in dem Projektordner wie folgt genutzt werden.
mise exec -- echo $MY_VAR # uses the variable
mise exec -- node --version # uses the defined node version
mise run hello # runs the task hello
Durch diese Features kann es weitere Tools ersetzen wie make oder auch direnv und ist damit geeignet für komplexere Projektszenarios. Es bietet weitere Features an wie das Verwalten von secrets oder auch Hooks, die bestimmte Aktionen automatisch ausführt, z.B. wenn man das Projekt via cd betritt oder wieder verlässt
Devbox – der einfache Einstieg in NIX
Mit Devbox4 betritt ein weiteres Tool die Bühne, das sich klar von SDKMAN!, asdf und mise abgrenzt. Während diese Werkzeuge primär versionsbasierte Toolchains verwalten, setzt Devbox konsequent auf Nix5 als Paketmanager und nutzt damit einen der mächtigsten Ansätze für reproduzierbare Entwicklungsumgebungen.
Nix ist aus technischer Sicht nahezu ideal: Pakete sind deklarativ beschrieben, vollständig isoliert, deterministisch gebaut und können nebeneinander in beliebigen Versionen existieren. Abhängigkeiten werden nicht implizit über das System aufgelöst, sondern explizit in einem rein funktionalen Modell beschrieben. Genau diese Eigenschaften machen Nix extrem gut geeignet für reproduzierbare Builds und identische Entwicklungsumgebungen – lokal wie im CI.
In der Praxis schreckt Nix jedoch viele Entwickler ab. Die eigene Sprache, das ungewohnte Denkmodell und Konzepte wie Derivations, Store Paths oder Flakes führen zu einer steilen Lernkurve. Für viele Teams ist der direkte Einstieg in Nix daher zu komplex und zu zeitaufwendig – insbesondere dann, wenn das eigentliche Ziel „nur“ eine stabile Entwicklungsumgebung ist.
Devbox setzt genau hier an. Es abstrahiert Nix auf eine Weise, die den größten Mehrwert nutzbar macht, ohne Entwickler mit der vollen Nix-Komplexität zu konfrontieren. Mit der Installation von devbox wird auch Nix als Paketmanager installiert.
curl -fsSL https://get.jetify.com/devbox | bash # installiert devbox
Ähnlich wie bei package.json oder mise.toml wird die Entwicklungsumgebung deklarativ über eine devbox.json beschrieben. Darin werden alle benötigten Tools und Abhängigkeiten projektspezifisch festgelegt – unabhängig vom globalen Systemzustand. Devbox kümmert sich im Hintergrund um die Auflösung und Installation über Nix, inklusive Caching und exakter Versionierung.
devbox init # erzeugt die devbox.json im lokalen Ordner
devbox add temurin-bin-24@24.0.2 # installiert Java
devbox add kubernetes-helm # installiert Helm als latest
Die erzeugte devbox.json sieht dann wie folgt aus:
{
...
"packages": [
"kubernetes-helm@latest",
"temurin-bin-24@24.0.2"
]
...
}
Das Ergebnis ist eine reproduzierbare Umgebung, die von jedem Teammitglied mit einem einzigen Kommando identisch aufgebaut werden kann.
devbox shell # öffnet die Shell mit allen benötigten Tools
Starting a devbox shell...
(devbox)
Devbox erlaubt zudem das Definieren von projektspezifischen Kommandos, die funktional an make erinnern. Diese Kommandos werden ebenfalls in der devbox.json hinterlegt und laufen automatisch in der definierten Umgebung. Das Konzept ähnelt den Task-Funktionen von mise, geht aber einen Schritt weiter, da die Ausführung immer an die deklarierte Nix-Umgebung gekoppelt ist. Dadurch lassen sich Build-, Test- oder Start-Kommandos zuverlässig und ohne implizite Abhängigkeiten definieren.
{
...
"shell": {
"scripts": {
"build": [
"./mvnw clean package"
]
}
}
...
}
Diese lassen sich dann mit devbox direkt aufrufen.
devbox run build
Info: Running script "build" on ...
...
Ein weiteres zentrales Feature ist die Möglichkeit, aus der Devbox-Konfiguration automatisch eine devcontainers.json zu erzeugen. Damit lässt sich exakt dieselbe Entwicklungsumgebung nicht nur lokal, sondern auch in einem Container – etwa in VS Code oder GitHub Codespaces – starten. Die lokale Nix-basierte Umgebung und die Container-Umgebung bleiben konsistent, ohne doppelte Pflege der Konfiguration
devbox generate devcontainer # erzeugt eine .devcontainer/devcontainer.json
Es gibt weitere Features wie Hooks, direnv-Integration oder auch das automatische Starten von notwendigen Services für die Entwicklung wie Datenbanken oder Messaging Systemen, die das Gesamtpaket abrunden.
Fazit
Vergleicht man die Ansätze von SDKMAN!, asdf, mise-en-place und devbox, wird schnell klar: Auf den ersten Blick verfolgen alle ein ähnliches Ziel, unterscheiden sich aber deutlich in Fokus, Umfang und Philosophie. Vom schlanken Versionsmanager bis hin zur vollständig reproduzierbaren Entwicklungsumgebung ist alles vertreten.
Welche Lösung am besten passt, hängt stark vom eigenen Projekt und den Anforderungen im Team ab. Für kleine Setups reicht oft ein einfaches Tool, während komplexere Umgebungen von deklarativen und stärker isolierten Ansätzen profitieren. Wichtig ist: Alle vorgestellten Werkzeuge erfüllen ihren Zweck zuverlässig und können die Einstiegshürde in neue Projekte spürbar senken – es gibt kaum gute Gründe, ganz auf solche Tools zu verzichten.
Am Ende ist die Entscheidung weniger eine Frage von „richtig oder falsch“, sondern davon, welche Features man tatsächlich braucht und wie viel Komplexität man bereit ist in Kauf zu nehmen. Persönlich überzeugt mise als guter Mittelweg: ausreichend mächtig, ohne unnötig kompliziert zu werden, und damit für viele Projekte ein sehr pragmatischer Begleiter im Entwickleralltag.