← Semua pembelajaran / Go Nol → Enterprise
Fase 0 · Fondasi Go & Tooling

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.

Sumber asli go.dev Resmi Rangkuman ~7 menit baca

Intisari

  • go.mod menyatakan modul, versi Go, dan dependensi langsung. go.sum mencatat 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 get menambah/menaikkan dependensi; go mod tidy merapikan; go build tidak 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.
  • replace untuk pengembangan lokal, vendor/ hampir tidak pernah dibutuhkan lagi.

Dua berkas, dua peran

BerkasIsinyaDitulis oleh
go.modNama modul, versi Go, daftar dependensi beserta versi minimumnyago get / go mod tidy
go.sumHash kriptografis tiap modul yang pernah diunduhToolchain — 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

BagianTugasnya
proxy.golang.orgCache modul publik. Modul yang sudah diunduh tetap tersedia meski repo aslinya dihapus.
sum.golang.orgLog transparansi hash. Menjamin isi v1.2.3 tidak pernah berubah diam-diam.
go.sumHash yang kamu percayai. Ketidakcocokan = build gagal, bukan peringatan.
GOPRIVATEPola 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.