Go Modules — dependensi & versi
Go memilih versi dependensi dengan aturan bernama Minimal Version Selection: bukan versi terbaru yang cocok, melainkan versi terendah yang memenuhi semua permintaan. Sekali paham, banyak kejutan hilang.
Intisari
go.modmenyatakan modul, versi Go, dan dependensi langsung.go.summencatat hash — keduanya di-commit.- Minimal Version Selection: Go memakai versi terendah yang memenuhi semua kebutuhan, bukan yang terbaru. Build hari ini dan tahun depan menghasilkan hal yang sama.
go getmenambah/menaikkan dependensi;go mod tidymerapikan;go buildtidak pernah diam-diam mengubah versi.- Mayor versi ≥ 2 masuk ke jalur import:
github.com/x/y/v3. Ini yang membuat dua versi mayor bisa hidup berdampingan. replaceuntuk pengembangan lokal,vendor/hampir tidak pernah dibutuhkan lagi.
Dua berkas, dua peran
| Berkas | Isinya | Ditulis oleh |
|---|---|---|
go.mod | Nama modul, versi Go, daftar dependensi beserta versi minimumnya | go get / go mod tidy |
go.sum | Hash kriptografis tiap modul yang pernah diunduh | Toolchain — jangan disentuh tangan |
module contoh.com/toko
go 1.25.0
require (
github.com/go-chi/chi/v5 v5.2.1
github.com/jackc/pgx/v5 v5.7.2
)
require (
github.com/jackc/pgpassfile v1.0.0 // indirect
golang.org/x/crypto v0.33.0 // indirect
)
Blok kedua bertanda // indirect: dependensi milik dependensimu. Ia ikut tercatat supaya build
bisa direproduksi persis, tapi kamu tidak memanggilnya langsung.
Minimal Version Selection
Ini perbedaan terbesar dari npm dan Composer, dan sumber banyak kelegaan. Kalau modulmu meminta
chi v5.2.1 dan sebuah dependensi meminta chi v5.1.0, Go memakai
v5.2.1 — versi tertinggi di antara yang diminta, bukan versi tertinggi yang
ada di internet.
Akibat praktisnya: go build tidak pernah diam-diam menaikkan versi apa pun.
Tidak ada padanan ^1.2.0 yang berubah arti besok pagi. Build hari ini dan build tahun depan
memakai kode yang sama persis, bahkan tanpa berkas lock terpisah — go.mod adalah
lock-nya. Kenaikan versi hanya terjadi saat kamu mengetik go get.
Perintah harian
go get github.com/go-chi/chi/v5 # tambah / naikkan ke versi terbaru
go get github.com/go-chi/chi/[email protected] # ke versi tertentu
go get -u ./... # naikkan semua dependensi langsung
go get -u=patch ./... # naikkan hanya versi patch — lebih aman
go mod tidy # tambah yang kurang, buang yang tak terpakai, rapikan go.sum
go mod download # unduh semuanya ke cache (dipakai di lapisan Docker)
go mod verify # cocokkan isi cache dengan hash di go.sum
go mod why github.com/x/y # kenapa modul ini ikut terbawa?
go list -m all # seluruh pohon dependensi yang benar-benar dipakai
go mod tidy adalah perintah yang wajib jalan bersih di CI. Kalau ia mengubah
berkas, artinya go.mod yang di-commit tidak mencerminkan import yang sebenarnya. Satu langkah
CI: jalankan go mod tidy lalu git diff --exit-code go.mod go.sum.
Versi mayor masuk ke jalur import
import (
"github.com/jackc/pgx/v5" // v5.x.x
"github.com/go-chi/chi/v5" // v5.x.x
"github.com/redis/go-redis/v9" // v9.x.x
)
Aturannya: mulai v2, nomor mayor menjadi bagian dari jalur import. Kelihatan aneh sebentar,
lalu terasa masuk akal — karena v2 memang paket yang berbeda, bukan paket yang sama
dengan API berbeda. Efek sampingnya: satu program boleh memakai v1 dan v3
sekaligus, yang membuat migrasi bertahap di aplikasi besar jadi mungkin.
Gejala khas saat lupa: go get github.com/jackc/pgx (tanpa /v5)
memasang versi 3 yang berumur bertahun-tahun, lalu semua contoh kode yang kamu salin gagal kompilasi.
Kalau sebuah pustaka sudah di v2+, jalur import-nya selalu berakhiran nomor.
replace untuk pengembangan lokal
# sementara arahkan dependensi ke salinan di disk
go mod edit -replace github.com/tim/pustaka=../pustaka
# kembalikan sebelum commit
go mod edit -dropreplace github.com/tim/pustaka
Untuk beberapa modul yang dikembangkan bersamaan, go work lebih rapi karena berkasnya
(go.work) tidak ikut ke git:
go work init ./api ./worker ./pustaka
go work use ./layanan-baru
replace yang tertinggal di go.mod adalah insiden yang menunggu. Ia
menunjuk jalur di laptop seseorang; di CI dan di produksi jalur itu tidak ada. Tambahkan pemeriksaan
grep -q "^replace" go.mod && exit 1 di pipeline kalau timmu lebih dari satu orang.
Rantai kepercayaan
| Bagian | Tugasnya |
|---|---|
proxy.golang.org | Cache modul publik. Modul yang sudah diunduh tetap tersedia meski repo aslinya dihapus. |
sum.golang.org | Log transparansi hash. Menjamin isi v1.2.3 tidak pernah berubah diam-diam. |
go.sum | Hash yang kamu percayai. Ketidakcocokan = build gagal, bukan peringatan. |
GOPRIVATE | Pola modul internal perusahaan yang harus dilewatkan dari proxy dan checksum publik. |
# modul internal: jangan lewat proxy publik, jangan dicatat ke sum.golang.org
go env -w GOPRIVATE=github.com/perusahaan/*
Kombinasi proxy + checksum database ini adalah alasan serangan rantai pasok gaya "maintainer mengganti isi
tag lama" tidak bekerja di Go: tag yang isinya berubah akan menghasilkan hash berbeda, dan build siapa pun
yang sudah punya go.sum akan langsung gagal.
Latihan: di proyek halo-mu, jalankan go get github.com/go-chi/chi/v5,
lihat isi go.mod dan go.sum. Lalu hapus baris import-nya dari kode dan jalankan
go mod tidy — perhatikan dependensinya hilang sendiri. Terakhir, jalankan
go mod why github.com/go-chi/chi/v5 sebelum dan sesudahnya, dan bandingkan jawabannya.
Rangkuman ini sengaja dipangkas ke bagian yang dipakai di roadmap. Buka sumber aslinya saat kamu butuh detail lengkap atau referensi parameter.