mise 버전 관리: nvm, pyenv, sdkman을 하나로 통합하는 방법

이번 포스팅에서는 nvm, pyenv, sdkman처럼 언어별로 흩어져 있던 버전 관리 도구를 하나로 통합하는 mise 버전 관리 도구에 대해서 정리하고자 한다. mise는 Rust로 작성된 통합 개발 환경 관리 도구로, 2026년 4월 현재 GitHub 스타 26,600개를 넘겼다. 버전 관리뿐 아니라 환경변수 관리와 task runner까지 하나의 바이너리에 들어 있어서, .zshrc에 nvm + sdkman + pyenv + direnv 초기화 스크립트를 덕지덕지 붙여놓던 환경을 정리할 수 있다.

nvm, pyenv, sdkman을 따로 쓰면 생기는 진짜 문제

백엔드 개발자의 로컬 환경은 대부분 비슷한 구조를 가진다. Java 프로젝트를 위한 sdkman, Node.js 빌드 도구를 위한 nvm, 데이터 처리 스크립트를 위한 pyenv가 각각 설치되어 있고, .sdkmanrc, .nvmrc, .python-version 파일이 프로젝트마다 흩어져 있다.

가장 먼저 느끼는 불편함은 shell 시작 속도이다. sdkman의 초기화 스크립트만 5줄이 넘고, nvm까지 더하면 .zshrc 로딩에 200~500ms가 추가된다. nvm은 shell을 열 때마다 Node.js 경로를 재계산하기 때문에 이 오버헤드를 피하기 어렵다.

버전 전환 방식도 도구마다 다르다. nvm은 nvm use를 수동으로 실행해야 하고, sdkman은 .sdkmanrc가 있는 디렉토리에 진입할 때 자동 전환을 지원하지만 별도 설정이 필요하다. pyenv는 .python-version을 읽긴 하지만 shim 방식이라 실행할 때마다 한 단계를 더 거친다.

그리고 새 팀원이 합류하면 온보딩 문서에 “sdkman 설치 후 sdk env install, nvm 설치 후 nvm use, pyenv 설치 후 pyenv install“을 각각 적어야 한다. 도구가 3개이니 설치 실패 지점도 3배이다. 이런 불편함이 쌓이면서 mise 버전 관리 같은 통합 도구에 관심을 갖게 되는 것이다.

mise는 어떻게 이 문제를 해결하는가

mise(발음: “미즈”, 프랑스어로 “배치하다”)는 이 도구들을 하나의 바이너리로 대체한다. 하나의 설정 파일(.mise.toml)에 프로젝트가 필요로 하는 모든 도구 버전을 선언하고, 디렉토리에 진입하면 자동으로 버전이 전환된다. Rust로 작성되어 있어서 shell 초기화와 버전 전환 모두 밀리초 단위로 동작한다.

mise가 대체하는 도구 목록을 정리하면 다음과 같다.

기존 도구역할mise 대체 기능
nvmNode.js 버전 관리[tools] node = "24"
pyenvPython 버전 관리[tools] python = "3.12"
sdkmanJava/Gradle/Maven 버전 관리[tools] java = "temurin-21"
direnv프로젝트별 환경변수[env] 섹션
Makefiletask runner[tasks] 섹션

공식 레지스트리를 보면 Node.js, Python, Ruby, Go, Java, Terraform, kubectl 등 실무에서 쓰는 도구 대부분이 등록되어 있다.

한 가지 짚고 넘어갈 점이 있다. mise를 설치한다고 해서 sdkman, nvm, pyenv가 함께 설치되는 것은 아니다. mise는 이 도구들에 의존하지 않고, 자체 백엔드로 각 언어의 바이너리를 직접 다운로드하여 ~/.local/share/mise/installs/ 경로에 관리한다. 즉, mise 하나만 설치하면 sdkman 없이도 JDK를, nvm 없이도 Node.js를 설치하고 전환할 수 있다. 기존에 sdkman이나 nvm이 이미 설치되어 있더라도 충돌 없이 공존하므로, mise를 먼저 써보고 만족스러우면 기존 도구를 정리하는 순서로 진행하면 된다.

설치와 Shell 연동 — 5분이면 끝난다

mise 버전 관리를 시작하려면 설치부터 해야 한다. 한 줄이면 된다. macOS, Linux 모두 동일하다.

# curl을 통한 설치 (권장)
curl https://mise.run | sh

# 또는 Homebrew를 통한 설치
brew install mise
ShellScript

실행하면 ~/.local/bin/mise에 바이너리가 설치된다. CI/CD 환경에서는 curl 방식이 간편하고, 로컬에서는 Homebrew도 괜찮다.

설치 후 사용 중인 shell에 맞는 활성화 스크립트를 추가해야 한다.

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

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

# Fish 사용자
echo '~/.local/bin/mise activate fish | source' >> ~/.config/fish/config.fish
ShellScript

사용 중인 shell에 맞는 activate 명령어 한 줄만 추가하면 된다. nvm, sdkman, pyenv가 각각 3~5줄씩 차지하던 것과 비교하면 .zshrc가 한결 깔끔해진다. 이후 shell을 새로 열면 mise가 현재 디렉토리의 .mise.toml을 읽어 도구 버전을 자동 전환한다.

설치가 정상적으로 완료되었는지 확인하려면 mise doctor를 실행한다.

mise doctor
ShellScript

mise의 설치 상태, shell 연동 여부, 설정 파일 경로를 진단해주고, 문제가 있으면 해결 방법까지 알려준다. 뭔가 안 될 때 가장 먼저 쳐보는 명령어이다.

mise 버전 관리 핵심 명령어

실제로 매일 쓰는 명령어는 몇 개 되지 않는다.

# 도구를 현재 프로젝트에 설치하고 .mise.toml에 기록
mise use node@24
mise use python@3.12
mise use java@temurin-21

# 글로벌 기본 버전 설정 (모든 디렉토리에서 적용)
mise use --global node@24

# 설치된 도구 목록 확인
mise list

# 특정 도구의 설치 가능한 버전 조회
mise list-all node

# 일회성 실행 (설치 없이 특정 버전으로 명령 실행)
mise exec node@22 -- node -v
ShellScript

mise use는 가장 자주 쓰는 명령어이다. 이 명령어 하나로 도구 설치와 .mise.toml 파일 업데이트가 동시에 이루어진다. --global 플래그를 붙이면 ~/.config/mise/config.toml에 글로벌 설정이 기록되어 어디서든 해당 버전이 기본값으로 적용된다.

mise exec는 프로젝트 설정을 변경하지 않고 특정 버전을 일회성으로 실행할 때 유용하다. 예를 들어 Node.js 22에서만 재현되는 버그를 테스트할 때 mise exec node@22 -- npm test처럼 사용할 수 있다.

.mise.toml로 프로젝트 환경을 선언하는 법

mise 버전 관리에서 가장 자주 다루게 되는 것은 .mise.toml 파일이다. 프로젝트가 필요로 하는 도구 버전, 환경변수, task를 이 파일 하나에 전부 적는다.

# .mise.toml — Spring Boot + React 모노레포 프로젝트 예시
[tools]
java = "temurin-21"       # Spring Boot 백엔드용 JDK
node = "24"               # React 프론트엔드용 Node.js
python = "3.12"           # 데이터 처리 스크립트용
"npm:prettier" = "latest" # npm 글로벌 패키지도 관리 가능

[env]
SPRING_PROFILES_ACTIVE = "local"
DATABASE_URL = "jdbc:postgresql://localhost:5432/myapp"
NODE_ENV = "development"

[tasks.dev-backend]
description = "Spring Boot 개발 서버 실행"
run = "cd backend && ./gradlew bootRun"

[tasks.dev-frontend]
description = "React 개발 서버 실행"
run = "cd frontend && npm run dev"

[tasks.dev]
description = "백엔드 + 프론트엔드 동시 실행"
depends = ["dev-backend", "dev-frontend"]
TOML

Java 21, Node.js 24, Python 3.12를 하나의 .mise.toml로 관리하는 예시이다. [env] 섹션에 환경변수를 적어두면 디렉토리에 진입할 때 자동으로 설정되니 .env 파일이나 direnv가 따로 필요 없다. [tasks] 섹션에는 자주 쓰는 명령어를 정의해두고 mise run dev로 호출한다.

이 파일을 Git에 커밋해두면 새 팀원은 clone 후 mise install 한 번이면 끝이다. README에 “sdkman으로 Java 21 설치, nvm으로 Node 24 설치, pyenv로 Python 3.12 설치”를 나열하던 시절과 비교하면 온보딩이 확 단순해진다.

Java 개발자를 위한 mise 버전 관리 활용법

sdkman에서 mise로 갈아타려는 Java 개발자를 위해 실무에서 자주 부딪히는 부분을 정리한다.

JDK 벤더 선택

mise는 여러 JDK 벤더를 지원한다. 벤더명을 버전 앞에 붙여서 지정한다.

# OpenJDK (기본값)
mise use java@21
# Eclipse Temurin (구 AdoptOpenJDK)
mise use java@temurin-21
# Azul Zulu
mise use java@zulu-21
# Amazon Corretto
mise use java@corretto-21
ShellScript

벤더를 지정하지 않으면 OpenJDK가 기본으로 설치된다. 운영 환경에서 Temurin이나 Corretto를 쓰고 있다면 로컬에서도 동일한 벤더를 명시해두는 편이 낫다. .mise.toml에는 이렇게 적으면 된다.

[tools]
java = "temurin-21"
Plaintext

이 한 줄이면 해당 디렉토리에 진입할 때마다 Temurin JDK 21이 자동으로 활성화된다.

JAVA_HOME 자동 설정

sdkman을 쓸 때와 마찬가지로 JAVA_HOME 설정이 필요한데, mise는 이것을 자동으로 잡아준다. export JAVA_HOME=...을 직접 적을 필요가 없다.

# mise가 Java를 활성화한 상태에서 확인
echo $JAVA_HOME
# 출력: ~/.local/share/mise/installs/java/temurin-21.0.x/

java -version
# 출력: openjdk version "21.0.x" ...
ShellScript

JAVA_HOME이 mise가 설치한 JDK 경로를 가리키고 있는 것을 확인할 수 있다. sdkman에서 sdk use java 21-tem을 실행하는 것과 같은 효과인데, 차이점은 디렉토리에 진입하는 것만으로 자동 전환이 된다는 것이다.

sdkman에서 mise로 마이그레이션

sdkman 사용법에 대해서 궁금하다면 다음 포스팅을 참고하기 바란다.
SDKMAN 설치부터 실전 활용까지: 자바 버전 관리 완벽 가이드 (2026)

이미 sdkman을 쓰고 있다면 옮기는 과정이 생각보다 수월하다. mise는 .sdkmanrc 파일을 그대로 읽을 수 있다.

# 기존 .sdkmanrc 내용 예시
java=21.0.2-tem

# mise가 이 파일을 읽으면 자동으로 temurin-21.0.2로 매핑
mise install
ShellScript

mise는 .sdkmanrc의 벤더 약칭(예: -tem은 Temurin, -zulu는 Azul Zulu)을 자동으로 해석한다. 따라서 팀에서 일부 개발자가 여전히 sdkman을 사용하더라도 동일한 .sdkmanrc 파일을 공유할 수 있다. 장기적으로는 .mise.toml로 전환하되, 과도기에는 두 설정 파일을 병행할 수 있다.

레거시 설정 파일 호환 — 팀 전환이 두렵지 않은 이유

mise 버전 관리 도구로 팀 단위 전환을 할 때 가장 걱정되는 부분은 “기존 설정 파일은 어떻게 하지?”인데, mise는 기존 도구의 설정 파일을 그대로 읽는다.

# mise가 자동으로 인식하는 레거시 설정 파일 목록
.nvmrc           # nvm (Node.js)
.node-version    # nodenv, fnm (Node.js)
.python-version  # pyenv (Python)
.ruby-version    # rbenv (Ruby)
.tool-versions   # asdf (멀티 언어)
.sdkmanrc        # sdkman (Java/Kotlin)
ShellScript

이 파일들이 프로젝트에 있으면 mise가 자동으로 읽어서 해당 버전을 적용한다. 즉, 팀 전체가 동시에 mise로 전환하지 않아도 된다. 옆자리 동료는 nvm을 쓰고 나는 mise를 쓰더라도, 같은 .nvmrc 파일로 동일한 Node.js 버전을 공유할 수 있다.

옮기는 순서는 이렇다. 먼저 mise를 설치하되 .nvmrc, .python-version 같은 기존 파일은 그대로 둔다. mise가 이 파일들을 읽으니 당장 바꿀 것은 없다. 팀원 대부분이 mise를 쓰기 시작하면 .mise.toml을 프로젝트에 추가한다. .mise.toml이 있으면 mise는 이 파일을 우선 참조한다. 마지막으로 레거시 파일을 정리하면 마이그레이션이 끝난다.

Task Runner로 Makefile까지 대체하기

여기까지가 mise 버전 관리의 핵심 기능인데, 사실 mise에는 task runner도 내장되어 있다. Makefile이나 package.jsonscripts 섹션을 대체할 수 있는 기능이다.

# .mise.toml — task 정의 예시
[tasks.build]
description = "프로젝트 빌드"
run = "gradle clean build -x test"

[tasks.test]
description = "전체 테스트 실행"
run = "gradle test"

[tasks.lint]
description = "코드 린트 검사"
run = "prettier --check 'src/**/*.{ts,tsx}'"

[tasks.deploy]
description = "배포 파이프라인 실행"
depends = ["build", "test"]   # build → test 순서로 실행 후 deploy
run = """
echo "Deploying to staging..."
./deploy.sh staging
"""
TOML

depends 필드가 task 간 실행 순서를 정한다. mise run deploy를 실행하면 build가 먼저 돌고, 성공하면 test가 돌고, 둘 다 통과해야 deploy가 실행된다. Makefile의 의존성 체인과 같은 개념이다.

# task 실행
mise run build

# task 목록 확인
mise tasks

# 파일 변경 감지 — 소스 변경 시 자동 재빌드
mise watch build
ShellScript

mise run으로 task를 실행하고 mise tasks로 목록을 확인한다. mise watch는 파일이 바뀔 때마다 지정된 task를 자동으로 다시 실행해주는데, 프론트엔드 개발에서 핫 리로드 대신 쓸 수 있다.

task를 .mise.toml 대신 파일 기반으로 정의할 수도 있다. mise-tasks/ 디렉토리에 실행 가능한 스크립트를 만들면 된다.

#!/usr/bin/env bash
# mise-tasks/setup — 프로젝트 초기 설정 스크립트
#MISE description="프로젝트 초기 환경 설정"

mise install
gradle wrapper
npm install --prefix frontend
echo "Setup complete."
ShellScript

mise-tasks/setup에 저장하고 chmod +x로 실행 권한을 주면 mise run setup으로 호출할 수 있다. 새 팀원에게 “이것만 실행하세요”라고 안내하면 도구 설치부터 의존성 다운로드까지 한 번에 끝난다.

마치며

지금까지 mise 버전 관리 도구의 설치부터 실전 프로젝트 적용까지 정리해 보았다. 솔직히 처음 mise를 접했을 때는 “또 하나의 버전 관리 도구”라고 생각했다. 이미 sdkman과 nvm으로 잘 굴러가는 환경이 있었기 때문이다. 그런데 프로젝트마다 .sdkmanrc, .nvmrc, .python-version이 각각 흩어져 있고, 새 팀원에게 이 세 도구의 설치법을 일일이 설명하는 상황이 반복되면서 생각이 달라졌다. .mise.toml 하나로 통합한 후로는 온보딩 가이드가 mise 하나로 끝나게 되었고, shell 시작 시간도 체감될 만큼 빨라졌다. 도구가 하나 줄어드는 것이 이렇게 편할 줄은 몰랐다.

FAQ

mise와 asdf의 차이점은 무엇인가?

mise는 asdf의 플러그인 생태계를 그대로 사용하면서 Rust로 완전히 재작성한 도구다. asdf 대비 10~100배 빠른 실행 속도를 보여주며, 환경변수 관리([env] 섹션)와 task runner([tasks] 섹션) 기능이 내장되어 있다. asdf는 셸 스크립트 기반이라 Windows를 지원하지 않지만 mise는 실험적으로 지원한다.

mise는 Windows에서도 사용할 수 있나?

2026년 4월 기준 mise는 Windows를 실험적(experimental)으로 지원한다. WSL 없이도 PowerShell에서 동작하지만, 일부 플러그인은 Unix 전용 빌드 스크립트에 의존하므로 완전한 호환은 아니다. 안정적인 사용을 원한다면 WSL2 환경에서 mise를 설치하는 것을 권장한다.

기존 .nvmrc, .sdkmanrc 파일이 있어도 mise로 전환할 수 있나?

가능하다. mise는 .nvmrc, .node-version, .python-version, .sdkmanrc, .tool-versions(asdf) 파일을 자동으로 인식한다. 기존 설정 파일을 그대로 두고 mise만 설치하면 되므로, 팀원 중 일부만 먼저 전환해도 충돌이 발생하지 않는다.

mise에서 특정 JDK 벤더를 선택할 수 있나?

mise use java@temurin-21, mise use java@corretto-21, mise use java@graalvm-21처럼 벤더명을 접두어로 지정하면 된다. mise list-all java 명령으로 설치 가능한 전체 JDK 목록을 확인할 수 있으며, Temurin, Corretto, GraalVM, Zulu 등 주요 벤더를 모두 지원한다.

mise를 CI/CD 파이프라인에서도 사용할 수 있나?

가능하다. GitHub Actions에서는 jdx/mise-action을 사용하면 .mise.toml에 선언된 도구를 자동 설치한다. Docker 환경에서는 curl https://mise.run | sh && mise install 두 줄이면 된다. 로컬과 CI에서 동일한 도구 버전을 보장하므로 “로컬에서는 되는데 CI에서 안 됨” 문제를 방지할 수 있다.

더 알아보기