Menu

go mod init과 Go 모듈: go.mod, go get, go mod tidy

Go 모듈이 동작하는 방식: go mod init으로 모듈 만들기, 모듈 경로 정하기, go get으로 의존성 추가하기, go mod tidy로 정리하기, go.sum의 용도, 그리고 로컬 개발을 위한 replace를 다룹니다.

이 페이지에는 실행 가능한 에디터가 있습니다 - 편집하고 실행하면 결과를 바로 볼 수 있습니다.

모듈은 루트에 go.mod 파일이 있는 Go 패키지들의 디렉터리 트리입니다. go.mod는 모듈의 이름을 정하고, 의존하는 다른 모든 모듈의 버전을 나열합니다. go mod init으로 만듭니다:

mkdir myapp
cd myapp
go mod init example.com/myapp
go: creating new go.mod: module example.com/myapp

만들어진 go.mod:

module example.com/myapp

go 1.24.5

빌드하기에는 이것으로 충분합니다. Go 1.16부터 모든 Go 프로젝트는 모듈이며, go build, go run ., go test는 모듈 없이는 동작하지 않습니다:

go: go.mod file not found in current directory or any parent directory; see 'go help modules'

모듈 경로 정하기

모듈 경로는 모듈 안의 모든 import 경로의 접두사입니다. 모듈이 example.com/myapp이라면 internal/store 디렉터리의 패키지는 example.com/myapp/internal/store로 import합니다.

상황모듈 경로
다른 사람이 import할 수 있는 GitHub 코드github.com/yourname/project
회사 코드yourcompany.com/project 또는 저장소 URL
개인 프로그램이나 연습example.com/myapp 또는 그냥 myapp
공개된 모듈의 버전 2 이상github.com/yourname/project/v2

라이브러리라면 go get이 경로로 저장소를 찾으므로 경로가 코드의 위치와 일치해야 합니다. 나만 실행하는 프로그램이라면 경로는 이름일 뿐입니다. go mod init fmtgo mod init strings처럼 표준 라이브러리 패키지와 같은 단어 하나는 피하세요. 그러면 빌드가 ambiguous import: found package fmt in multiple modules로 실패합니다.

예전 GOPATH 구조 밖에서 인자 없이 go mod init을 실행하면 실패합니다:

go: cannot determine module path for source directory /home/ana/myapp (outside GOPATH, module path must be specified)

경로를 지정하세요.

의존성 추가하기

import를 쓰고 Go가 가져오게 하세요. main.gogithub.com/google/uuid를 import한다고 합시다. 모듈이 그것을 알기 전에 빌드하면 분명한 안내가 나옵니다:

main.go:6:2: no required module provides package github.com/google/uuid; to add it:
	go get github.com/google/uuid

둘 중 어느 명령으로든 해결됩니다:

go get github.com/google/uuid
# or, to sync go.mod with every import in the module:
go mod tidy

go get은 무엇을 바꿨는지 보고합니다:

go: downloading github.com/google/uuid v1.6.0
go: added github.com/google/uuid v1.6.0

go mod tidy는 import를 어떻게 해석했는지 보고합니다:

go: finding module for package github.com/google/uuid
go: downloading github.com/google/uuid v1.6.0
go: found github.com/google/uuid in github.com/google/uuid v1.6.0

이제 go.modrequire 줄이 생겼습니다:

module example.com/myapp

go 1.24.5

require github.com/google/uuid v1.6.0

버전을 지정한 go get

명령효과
go get pkgpkg를 최신 릴리스로 추가, 이미 필요하면 현재 버전 유지
go get pkg@v1.5.0정확히 v1.5.0 사용(업그레이드 또는 다운그레이드)
go get pkg@latest최신 릴리스로 이동
go get pkg@abc1234특정 커밋 사용(의사 버전으로 기록)
go get -u ./...모든 의존성을 최신 마이너 또는 패치 릴리스로 업그레이드
go get -u=patch ./...최신 패치 릴리스로만 업그레이드
go get pkg@none요구 사항 제거
go get go@1.24모듈의 최소 Go 버전 올리기

go getgo.mod를 바꿉니다. 더 이상 프로그램을 빌드하거나 설치하지 않으며, Go 1.18부터 그것은 go install pkg@version이 하는 일입니다.

간접 의존성

// indirect가 붙은 요구 사항은 코드가 직접 import하지는 않지만 빌드에 필요한 모듈입니다. Go 1.17부터 go.mod는 빌드에 패키지를 제공하는 모든 모듈을 나열하므로, 의존성의 의존성이 이 표시와 함께 여기에 나타납니다. 이 표시는 go mod tidy가 관리하며 직접 추가하지 않습니다.

go mod tidy

import를 추가하거나 제거할 때마다 go mod tidy를 실행하세요. 이 명령은:

  • import했는데 빠진 패키지의 요구 사항을 추가하고,
  • 더 이상 아무것도 import하지 않는 요구 사항을 제거하며,
  • 빌드에 필요한 go.sum 항목을 추가하고 오래된 항목을 버립니다.

테스트와 모든 빌드 태그 조합을 포함해 모듈의 모든 패키지를 살펴보므로, 여러분의 플랫폼에서는 쓰이지 않는 것처럼 보이는 의존성을 남기기도 합니다. 커밋마다 go mod tidy를 실행하고 CI에서 차이가 생기지 않는지 확인하면 go.mod를 정직하게 유지할 수 있습니다.

go.sum

go.sum은 빌드가 쓰는 모든 모듈 버전의 해시를 기록합니다:

github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=

첫 번째 줄은 모듈 파일들의 해시이고, 두 번째 줄은 그 go.mod만의 해시입니다. go 명령은 모듈을 내려받을 때 해시를 go.sum과 공개 체크섬 데이터베이스(sum.golang.org)에 대조하므로, 변조되었거나 몰래 바뀐 릴리스는 빌드를 실패시킵니다. go.sumgo.mod와 함께 커밋하고, 절대 직접 편집하지 마세요.

Go가 버전을 고르는 방식

Go는 **최소 버전 선택(minimal version selection)**을 씁니다. 각 모듈은 의존성마다 필요한 최소 버전을 나열하고, 빌드는 그 최솟값들 중 가장 높은 것을 쓰며 그보다 새로운 것은 절대 쓰지 않습니다. 여러분의 모듈이 uuid v1.5.0을 요구하고 의존성이 uuid v1.6.0을 요구하면, v1.7.0이 있더라도 빌드는 v1.6.0을 씁니다. 누군가 go get으로 요청하지 않는 한 아무것도 업그레이드되지 않습니다.

그 결과 잠금 파일 없이도 빌드를 재현할 수 있습니다. go.mod와 의존성 그래프가 모든 버전을 완전히 결정합니다. go list -m all이 그 결과를 출력합니다:

go list -m all
example.com/myapp
github.com/google/uuid v1.6.0

메이저 버전

v2 이상의 모듈은 경로에 메이저 버전을 포함해야 합니다: github.com/yourname/project/v2. import 경로도 함께 바뀌므로 projectproject/v2는 서로 다른 모듈이며 한 빌드에 둘 다 있을 수 있습니다. 이것이 호환성을 깨는 변경에 대한 Go의 규칙이고, github.com/jackc/pgx/v5 같은 import를 보게 되는 이유입니다.

replace: 의존성을 로컬에서 수정하기

의존성의 변경 사항을 공개하기 전에 테스트하려면 그 경로를 로컬 디렉터리로 가리키게 하세요:

module example.com/myapp

go 1.24.5

require example.com/mylib v1.2.0

replace example.com/mylib => ../mylib

또는 명령줄에서:

go mod edit -replace example.com/mylib=../mylib
go mod tidy

그 디렉터리에는 자체 go.mod가 있어야 합니다. replace는 이 모듈을 직접 빌드할 때만 적용되고 다른 사람이 이 모듈에 의존할 때는 적용되지 않으므로, 릴리스 태그를 달기 전에 제거하는 것을 잊지 마세요.

여러 모듈의 go.mod를 건드리지 않고 한꺼번에 편집하려면 Go 1.18에서 추가된 워크스페이스를 쓰세요:

go work init . ../mylib

그러면 로컬 mylib이 우선하게 만드는 go.work 파일이 생깁니다. 팀 전체가 같은 구조를 쓰지 않는 한 go.work는 버전 관리에 넣지 마세요.

도구 의존성 (Go 1.24)

Go 1.24에는 tool 지시어가 추가되어, 코드 생성기와 린터를 전역으로 설치하는 대신 go.mod에서 버전을 관리할 수 있습니다:

go get -tool golang.org/x/tools/cmd/stringer
go tool stringer -type=Color

func init은 다른 것이다

"golang init"을 검색하는 사람은 go mod init과 관계없는 init 함수를 찾는 경우가 많습니다. 어느 패키지든 func init()을 선언할 수 있습니다. 인자를 받지 않고, 여러분의 코드에서 호출할 수 없으며, 패키지 수준 변수가 설정된 뒤 main 전에 자동으로 한 번 실행됩니다:

파일 하나에 init 함수가 여러 개 있을 수 있고, 나타나는 순서대로 실행됩니다. import한 패키지가 먼저 자기 초기화를 마칩니다. init은 작게 유지하세요. 실패할 수 있는 작업은 main에서 호출하는 평범한 함수로 두는 편이 처리하고 테스트하기 쉽습니다.

비공개 모듈과 프록시

기본적으로 goproxy.golang.org를 통해 모듈을 내려받습니다. 이 프록시는 비공개 저장소를 볼 수 없으므로 어떤 경로가 비공개인지 Go에 알려 주세요:

go env -w GOPRIVATE=github.com/yourcompany/*

GOPRIVATE와 일치하는 모듈은 git 자격 증명으로 저장소에서 직접 가져오며 체크섬 데이터베이스를 건너뜁니다.

자주 묻는 질문

go mod init은 무엇을 하나요?

현재 디렉터리에 go.mod 파일을 만들어 그 디렉터리를 모듈의 루트로 만듭니다. go mod init example.com/myapp은 모듈 경로와 Go 버전을 기록합니다:

module example.com/myapp

go 1.24.5

go buildgo get을 쓰기 전에 프로젝트당 한 번 실행하세요.

go mod init의 모듈 경로로는 무엇을 써야 하나요?

다른 사람이 import할 때 코드를 가져올 주소이며, 보통 저장소 경로입니다: go mod init github.com/yourname/project. 아무도 import하지 않을 프로그램이라면 어떤 이름이든 되지만(go mod init myapp), example.com/myapp처럼 점이 들어간 도메인 형태의 경로를 쓰면 표준 라이브러리 패키지 이름과의 충돌을 피할 수 있습니다.

go get과 go mod tidy의 차이는 무엇인가요?

go get pkg@version은 의존성을 추가하거나 버전을 바꿉니다. go mod tidy는 소스 파일을 읽어서 import에 필요하지만 go.mod에 없는 모듈을 추가하고, 아무것도 import하지 않는 요구 사항을 제거하고, go.sum을 갱신합니다. 흔한 흐름은 import를 쓴 뒤 go mod tidy를 실행하는 것입니다.

go.sum을 커밋해야 하나요?

네. go.sum에는 빌드가 쓰는 모든 모듈 버전의 암호학적 해시가 들어 있습니다. 커밋해 두면 go 명령이 모두가 바이트 단위로 동일한 의존성을 내려받는지 검증할 수 있습니다. 직접 편집하지 마세요. go mod tidy가 관리합니다.

"golang init"은 go mod init과 같은 것인가요?

아니요, 단어만 같은 다른 것입니다. go mod initgo.mod를 만드는 터미널 명령입니다. func init()은 Go 코드에 작성하는 함수로, 패키지 변수가 초기화된 뒤 main 전에 자동으로 한 번 실행됩니다.

Coddy programming languages illustration

Coddy로 코딩 배우기

시작하기