본문 바로가기
macOS & Macintosh

SDKMAN으로 macOS JDK 여러 버전 관리하기

동교동삼거리·2026년 9월 21일·조회 1

맥에서 자바를 여러 버전 쓰다 보면 어느 순간 java -version과 IDE가 서로 다른 JDK를 가리키는 상황을 만난다. 프로젝트 하나는 17이 필요하고 다른 하나는 아직 8에 묶여 있는데, 여기에 Homebrew로 깔아둔 JDK와 예전에 인스톨러로 넣은 시스템 JDK까지 섞이면 JAVA_HOME이 어디를 보는지 매번 헷갈린다. 예전에 .zshrcJAVA_HOME을 손으로 갈아끼우던 글을 쓴 적이 있는데, 프로젝트가 서너 개만 넘어가도 그 방식은 금방 한계가 온다.

결론부터 말하자면, SDKMAN을 쓰면 JDK 여러 개를 한 곳에서 설치하고 .sdkmanrc 파일로 디렉터리에 들어갈 때마다 자동으로 버전을 바꿀 수 있다. Homebrew나 시스템 JDK와 충돌하는 것 같으면 대부분 PATH 순서와 JAVA_HOME 문제이고, 이건 SDKMAN에 관리를 넘기고 수동 설정을 걷어내면 정리된다. 아래에서 설치, 자동 전환, 충돌 정리를 차례로 살펴본다.

1. SDKMAN이 무엇인가

SDKMAN은 자바 계열 SDK를 사용자 홈 디렉터리 안에서 설치하고 전환해주는 커맨드라인 도구다. 관리 대상은 JDK뿐 아니라 Gradle, Maven, Kotlin, Scala 같은 것도 포함한다. 설치물은 전부 ~/.sdkman/candidates/ 아래에 들어가고, 시스템 영역(/Library, /usr)은 건드리지 않는다. 그래서 sudo 없이 여러 버전을 깔고 지울 수 있다.

핵심은 셸이 시작될 때 SDKMAN이 PATH 앞쪽에 자기 candidates 경로를 끼워 넣는다는 점이다. java를 입력하면 이 경로가 먼저 잡히므로, SDKMAN이 활성화한 버전이 시스템에 뭐가 깔려 있든 우선한다. 이 동작을 이해하면 뒤에서 다룰 충돌 문제의 절반은 이미 설명된다.

2. 설치

맥에는 curl과 zip이 기본으로 있으므로 별도 준비물은 없다. 공식 설치 명령을 그대로 실행한다.

$ curl -s "https://get.sdkman.io" | bash

설치가 끝나면 안내대로 새 셸에서 초기화 스크립트를 불러온다. zsh를 쓰면 ~/.zshrc 끝에 다음 한 줄이 자동으로 추가된다.

export SDKMAN_DIR="$HOME/.sdkman"
[[ -s "$HOME/.sdkman/bin/sdkman-init.sh" ]] && source "$HOME/.sdkman/bin/sdkman-init.sh"

터미널을 새로 열고 버전을 확인한다. 스크립트 버전과 네이티브 버전이 함께 나오면 설치가 된 것이다. 버전 숫자는 설치 시점에 따라 다를 수 있다.

$ sdk version
SDKMAN!
script: 5.19.0
native: 0.5.0

여기까지면 기본적인 설치는 됐다고 보면 된다.

3. JDK 여러 버전 설치와 전환

설치 가능한 자바 목록을 본다. Temurin, Amazon Corretto, Azul Zulu, GraalVM 등 벤더별로 정렬돼 나온다.

$ sdk list java
================================================================================
 Vendor        | Use | Version      | Dist    | Status     | Identifier
--------------------------------------------------------------------------------
 Temurin       |     | 21.0.4       | tem     |            | 21.0.4-tem
               |     | 17.0.12      | tem     |            | 17.0.12-tem
               |     | 11.0.24      | tem     |            | 11.0.24-tem
 Corretto      |     | 21.0.4       | amzn    |            | 21.0.4-amzn
 ...

맨 오른쪽 Identifier가 설치할 때 쓰는 정확한 이름이다. 벤더를 딱히 가리지 않는다면 Temurin(-tem)이 무난하다. 필요한 버전을 식별자로 설치한다.

$ sdk install java 21.0.4-tem
$ sdk install java 17.0.12-tem
$ sdk install java 11.0.24-tem

처음 설치한 버전은 자동으로 기본값(default)이 된다. 현재 셸에서만 잠깐 다른 버전으로 바꾸려면 use, 시스템 전역 기본값을 바꾸려면 default를 쓴다.

$ sdk use java 17.0.12-tem
Using java version 17.0.12-tem in this shell.

$ sdk default java 21.0.4-tem
Default java version set to 21.0.4-tem

use는 그 터미널 창을 닫으면 사라지고, default는 새로 여는 셸에도 적용된다. 이 둘의 차이를 헷갈리면 "분명 바꿨는데 새 터미널에서 원래대로 돌아온다"는 상황을 만난다. 그때는 use만 했을 가능성이 높다.

확인은 늘 같은 명령으로 한다.

$ java -version
openjdk version "17.0.12" 2024-07-16
OpenJDK Runtime Environment Temurin-17.0.12+7 (build 17.0.12+7)
OpenJDK 64-Bit Server VM Temurin-17.0.12+7 (build 17.0.12+7, mixed mode)

4. .sdkmanrc로 프로젝트별 자동 전환

.sdkmanrc는 프로젝트 최상위 디렉터리에 두는 설정 파일이다. 그 프로젝트에서 어떤 SDK 버전을 쓸지 적어두면, 디렉터리에 들어갈 때 SDKMAN이 그 버전으로 맞춰준다. 팀원이 같은 저장소를 받아도 동일한 JDK를 쓰게 만드는 용도로 유용하다.

프로젝트 폴더로 이동한 뒤 현재 활성 버전으로 파일을 생성한다.

$ cd ~/work/my-service
$ sdk env init
.sdkmanrc created.

생성된 파일 내용은 다음과 같다. 필요하면 값을 직접 고친다.

$ cat .sdkmanrc
# Enable auto-env through the sdkman_auto_env config
# Add key=value pairs of SDKs to use below
java=17.0.12-tem

이 파일을 커밋해두면 다른 사람이 sdk env install 한 번으로 필요한 JDK를 채워 넣을 수 있다.

$ sdk env install

수동으로 적용할 때는 그 디렉터리에서 sdk env를 실행한다. 원래 기본값으로 되돌리려면 sdk env clear다.

$ sdk env
Using java version 17.0.12-tem in this shell.

디렉터리에 들어가면 자동으로 바꾸기

매번 sdk env를 치는 게 번거로우면 자동 전환을 켠다. ~/.sdkman/etc/config를 열어 다음 값을 true로 바꾼다.

sdkman_auto_env=true

셸을 새로 열면 적용된다. 이제 .sdkmanrc가 있는 디렉터리로 cd하면 그 버전이 활성화되고, 디렉터리를 벗어나면 기본값으로 되돌아간다.

$ cd ~/work/my-service
Using java version 17.0.12-tem in this shell.
$ java -version
openjdk version "17.0.12" 2024-07-16 ...

$ cd ~
Restored java version to 21.0.4-tem (default)

이 자동 전환은 셸의 PROMPT_COMMAND 훅으로 동작한다. 프롬프트가 그려지기 직전에 현재 디렉터리에 .sdkmanrc가 있는지 보고, 있으면 sdk env를 실행하는 방식이다. 별도의 신뢰 확인이나 승인 절차는 없다. auto_env를 켜두면 해당 파일이 있는 디렉터리에서 조건 없이 적용된다. 그래서 신뢰할 수 없는 저장소를 받아 열 때는 .sdkmanrc 내용을 한 번 확인하는 습관이 낫다.

5. Homebrew, 시스템 JDK와의 충돌 잡기

맥에서 자바가 꼬이는 대부분의 원인은 SDKMAN 밖에서 설치된 JDK가 PATHJAVA_HOME을 붙잡고 있는 경우다. 먼저 지금 무엇이 잡히는지 확인한다.

$ which java
/Users/you/.sdkman/candidates/java/current/bin/java

$ echo $JAVA_HOME
/Users/you/.sdkman/candidates/java/current

정상이면 위처럼 둘 다 ~/.sdkman/candidates/java/current를 가리킨다. 만약 /opt/homebrew/opt/openjdk/.../Library/Java/JavaVirtualMachines/...가 나온다면 다른 설치물이 우선순위를 가로챈 것이다.

macOS의 java_home 심링크

맥에는 /usr/bin/java가 실제 JDK를 직접 가리키지 않고 /usr/libexec/java_home이라는 도구를 통해 시스템에 등록된 JDK를 찾는 구조가 있다. 인스톨러로 넣은 Oracle JDK나 Temurin pkg는 /Library/Java/JavaVirtualMachines/에 등록된다. 무엇이 등록돼 있는지 이 명령으로 본다.

$ /usr/libexec/java_home -V
Matching Java Virtual Machines (2):
    21.0.4 (arm64) "Eclipse Adoptium" - "OpenJDK 21.0.4" /Library/Java/JavaVirtualMachines/temurin-21.jdk/...
    17.0.9 (arm64) "Oracle Corporation" - "Java SE 17.0.9" /Library/Java/JavaVirtualMachines/jdk-17.jdk/...

SDKMAN이 설치한 JDK는 여기에 등록되지 않는다. 그래서 두 관리 체계가 공존하면 셸에서는 SDKMAN 버전이, java_home을 참조하는 일부 도구에서는 시스템 버전이 잡히는 엇갈림이 생긴다. 관리를 SDKMAN으로 통일하기로 했으면 시스템 등록 JDK는 남겨두더라도 JAVA_HOME은 SDKMAN 쪽으로 고정하는 게 깔끔하다.

수동 JAVA_HOME 설정을 걷어낸다

가장 흔한 사고는 .zshrc.zprofile에 예전에 넣어둔 JAVA_HOME export가 살아 있는 경우다. SDKMAN 초기화 줄보다 뒤에 이런 줄이 있으면 SDKMAN 설정을 덮어쓴다.

# 이런 줄이 있으면 지운다
export JAVA_HOME=$(/usr/libexec/java_home -v 17)
export PATH="/opt/homebrew/opt/openjdk/bin:$PATH"

이 줄들을 지우고 JAVA_HOME 관리는 SDKMAN에 맡긴다. SDKMAN은 버전을 전환할 때마다 JAVA_HOME을 알아서 현재 버전에 맞춰준다. 셸 설정에서 자바 관련 PATH, JAVA_HOME 조작을 전부 제거하고 SDKMAN 초기화 줄만 남기는 것이 목표다.

Homebrew로 깐 openjdk가 있다면, 자바 실행 파일을 시스템에 링크하는 brew link를 걸어두지 않는 편이 충돌을 줄인다. 이미 링크했다면 해제한다.

$ brew unlink openjdk

정리한 뒤 새 터미널을 열고 다시 which javaecho $JAVA_HOME이 둘 다 ~/.sdkman 경로를 가리키는지 확인한다. 여기까지 맞으면 IDE에도 같은 JDK를 물려주면 된다. IntelliJ IDEA라면 프로젝트 SDK 경로로 ~/.sdkman/candidates/java/<버전>을 직접 지정한다.

6. 정리

맥에서 JDK를 여러 개 쓴다면 SDKMAN 한 곳으로 설치와 전환을 모으고, 프로젝트마다 .sdkmanrc를 커밋해 자동 전환을 거는 방식이 관리 부담이 가장 적다. 충돌이 의심되면 which javaecho $JAVA_HOME부터 확인하고, 셸 설정에 남은 수동 JAVA_HOME export와 Homebrew 링크를 걷어내는 것으로 대부분 해결된다. 시스템에 인스톨러 JDK가 등록돼 있어도 JAVA_HOME만 SDKMAN 쪽으로 고정하면 엇갈림은 사라진다.

자주 묻는 질문

sdk use와 sdk default는 무엇이 다른가?

sdk use java <버전>은 명령을 실행한 그 셸 세션에서만 버전을 바꾸고, 터미널을 닫으면 사라진다. sdk default java <버전>은 전역 기본값을 바꿔 새로 여는 셸에도 적용된다. 새 터미널에서 자꾸 원래 버전으로 돌아간다면 use만 했을 가능성이 높다.

.sdkmanrc 자동 전환이 동작하지 않는다.

~/.sdkman/etc/config에서 sdkman_auto_env=true인지 확인하고, 설정을 바꿨다면 새 터미널을 열어야 적용된다. 이 기능은 셸의 PROMPT_COMMAND 훅으로 디렉터리 진입 시 sdk env를 실행하는 방식이며, 별도의 신뢰 승인 절차는 없다. 자동 전환을 켜기 전이라면 그 디렉터리에서 sdk env를 직접 실행하면 된다.

which java는 SDKMAN 경로인데 JAVA_HOME은 다른 곳을 가리킨다.

.zshrc나 .zprofile에 예전에 넣어둔 export JAVA_HOME 줄이 SDKMAN 초기화 뒤에 남아 덮어쓰는 경우가 대부분이다. 자바 관련 JAVA_HOME과 PATH 조작 줄을 지우고 SDKMAN 초기화 줄만 남긴 뒤 새 터미널을 열어 확인한다.

SDKMAN으로 깐 JDK가 /usr/libexec/java_home -V 목록에 안 보인다.

정상이다. SDKMAN은 JDK를 ~/.sdkman/candidates/ 아래에만 설치하고 macOS 시스템 JDK 등록소(/Library/Java/JavaVirtualMachines)에는 넣지 않는다. 셸에서는 SDKMAN 버전이 PATH 우선순위로 잡히므로 java -version으로 확인하면 된다.

SDKMAN과 Homebrew openjdk를 같이 써도 되나?

설치 자체는 공존하지만 Homebrew openjdk를 brew link로 시스템에 링크해두면 PATH가 엇갈릴 수 있다. 관리를 SDKMAN으로 통일하기로 했다면 brew unlink openjdk로 링크를 풀고, 셸의 자바 PATH 조작을 제거해 SDKMAN에 맡기는 것이 충돌이 적다.

관련 글

댓글 0

로그인 후 댓글을 남길 수 있습니다.

아직 댓글이 없습니다.