Go modülü, birlikte sürümlenip dağıtılan paketlerin topluluğudur ve kök dizinindeki go.mod dosyasıyla tanımlanır. Yeni bir modülü go mod init example.com/proje ile başlatırsınız; kodunuz bir paketi içe aktardıkça go mod tidy eksik bağımlılıkları go.mod dosyasına ekler, kullanılmayanları siler ve indirilen modüllerin kriptografik özetlerini go.sum dosyasına yazar. Belirli bir sürüme geçmek için go get modül@sürüm kullanılır.

Bu yazıda modül kavramını Go Modules Reference ve go.mod referansına dayanarak adım adım ele alıyoruz: go.mod yönergelerinin her biri ne işe yarar, go satırı neden artık bir zorunluluktur, Go hangi bağımlılık sürümünü neden seçer, go.sum neyi korur ve henüz yayımlanmamış yerel bir modülü replace ya da çalışma alanı (workspace) ile nasıl kullanırsınız. Örneklerin tamamı Go 1.27.3 ile, ağ bağlantısı gerektirmeyen yerel modüllerle çalıştırıldı. Go diline yeni başlıyorsanız önce Go öğrenme rehberi sayfasındaki sırayı izleyebilir, paketlerin modül içinde nasıl düzenlendiğini ise Go paket yapısı ve import yazısında okuyabilirsiniz.

Modül, paket ve modül yolu

Go'da kod iki katmanda düzenlenir. Paket, aynı dizinde bulunan ve birlikte derlenen kaynak dosyalarıdır. Modül ise bir veya daha fazla paketi kapsayan, birlikte sürümlenen birimdir. go.mod dosyasının bulunduğu dizin modülün kök dizinidir; modül bu dizindeki ve alt dizinlerdeki paketleri, başka bir go.mod içeren alt dizine kadar kapsar. go komutunu çalıştırdığınız dizini içeren modüle ana modül (main module) denir.

module satırında yazan modül yolu iki iş görür. Birincisi, modüldeki tüm paketlerin import yolunun ön ekidir: example.com/magaza modülündeki sepet dizinindeki paket example.com/magaza/sepet olarak içe aktarılır. İkincisi, modül başkalarınca indirilecekse go komutunun kaynağı arayacağı adresi gösterir. Bu nedenle belgeler, modülü hiç yayımlamayı düşünmüyor olsanız bile depo adresinizi (ör. github.com/kullanici/proje) kullanmanızı önerir; ileride yayımlarsanız yeniden adlandırmanız gerekmez. Depo adresi henüz belli değilse sahip olduğunuz bir alan adı ya da şirket adı gibi çakışmayacak bir ön ek seçin. example ve test ön ekleri belgelerde örnekler ve testler için ayrılmıştır; bu yazıdaki example.com/... yolları da bu yüzden kullanıldı.

go mod init ile modül başlatmak

go mod init bulunduğunuz dizinde yeni bir go.mod oluşturur; dosya zaten varsa çalışmaz. Argüman olarak modül yolunu verirsiniz:

bash
$ mkdir metin && cd metin
$ go mod init example.com/metin
go: creating new go.mod: module example.com/metin
$ cat go.mod
module example.com/metin

go 1.27.3

Oluşan dosyada iki satır vardır: modül yolu ve go yönergesi. go satırına yazılan sürüm, komutu çalıştıran araç takımına göre değişir; bu denemede Go 1.27.3, kendi sürümünü yazdı. Modülünüzün daha eski Go sürümleriyle de derlenmesini istiyorsanız satırı go mod edit -go=1.25.0 gibi bir komutla düşürebilirsiniz. Modül yolunu sonradan değiştirmek mümkündür (go mod edit -module), ancak modülü kullanan herkesin import satırlarını da değiştirmesi gerekeceği için yolu baştan doğru seçmek en kolayıdır.

Modül içinde bir paket yazalım. Bu dosya metin dizininde duruyor ve dışa aktarılan tek bir fonksiyon içeriyor:

go
// Package metin, küçük metin yardımcıları içerir.
package metin

import "strings"

// Selamla, verilen ada Türkçe bir selam döndürür.
func Selamla(ad string) string {
	return "Merhaba, " + strings.TrimSpace(ad) + "!"
}

go.mod yönergeleri tek tek

go.mod yönergeleri tek tek: module, Gereken en düşük Go sürümü, toolchain, godebug

go.mod satır tabanlı bir dosyadır ve her satır bir yönergeyle başlar. Elle düzenleyebilirsiniz, ancak Go belgeleri değişiklikleri go get, go mod tidy ve go mod edit gibi komutlarla yapmanızı önerir; bu komutlar dosyanın tutarlı ve geçerli kalmasını sağlar. Aşağıdaki tablo go.mod referansındaki yönergeleri özetler:

YönergeNe yaparNot
moduleModül yolunu bildirirv2 ve sonrası için yol /v2 gibi bir ekle biter
goGereken en düşük Go sürümüGo 1.21 ile zorunlu hâle geldi
toolchainÖnerilen araç takımıYalnızca ana modülde etkili
godebugVarsayılan GODEBUG ayarlarıYalnızca ana modülün main paketlerine uygulanır
requireBir bağımlılığın en düşük sürümügo get ve go mod tidy yönetir
toolGo ile yazılmış geliştirici aracıGo 1.24 ile geldi, go tool ile çalışır
replaceBir modülü başka sürüm ya da yerel dizinle değiştirirYalnızca ana modülde uygulanır
excludeBelirli bir sürümü dışlarYalnızca ana modülde uygulanır
retractYayımlanmış kendi sürümünüzü geri çekerModülün en son sürümünden okunur
ignoreDesen eşleşmesinde dizinleri yok sayarGo 1.25 ile geldi, yalnızca ana modülde

Burada en çok gözden kaçan ayrıntı, replace ve exclude yönergelerinin yalnızca ana modülde geçerli olmasıdır. Sizin modülünüzü bağımlılık olarak kullanan başka bir proje, sizin replace satırlarınızı görmez. Yani replace geçici geliştirme kolaylığıdır, bağımlılarınıza dayatabileceğiniz bir ayar değildir.

go satırı artık bir alt sınırdır

go satırı artık bir alt sınırdır

go.mod referansına göre go yönergesi Go 1.21'den önce yalnızca bilgi amaçlıydı; Go 1.21 ile birlikte zorunlu bir alt sınıra dönüştü ve araç takımları kendilerinden yeni bir Go sürümü isteyen modülleri kullanmayı reddeder. Go Toolchains belgesi bunun varsayılan davranışını da açıklar: GOTOOLCHAIN varsayılan olarak auto değerindedir ve go satırı paketle gelen araç takımından yeniyse go komutu daha yeni araç takımını PATH'te arar ya da indirir. Bu makinede örnekler GOTOOLCHAIN=local ile çalıştırıldığı için indirme kapalıydı ve sonuç doğrudan hata oldu:

bash
$ go mod edit -go=1.28
$ go run .
go: go.mod requires go >= 1.28 (running go 1.27.3; GOTOOLCHAIN=local)

go satırı derleyicinin hangi dil özelliklerine izin vereceğini de belirler. Belgedeki kurala göre derleyici, modüldeki paketlerde go satırındaki sürümden sonra gelen dil özelliklerini reddeder. Aşağıdaki programda Go 1.22 ile gelen tamsayı üzerinde range kullanılıyor (ayrıntısı Go for döngüsü ve range yazısında). go.mod dosyasında go 1.21 yazarken derleme şu hatayla durur, satırı go 1.22 yaptığınızda ise program çalışır:

go
package main

import "fmt"

func main() {
	for i := range 3 {
		fmt.Println(i)
	}
}
text
# example.com/eski
./main.go:6:17: cannot range over 3 (untyped int constant): requires go1.22 or later (-lang was set to go1.21; check go.mod)

Hata mesajı sorunun kaynağını açıkça söylüyor: check go.mod. Eski bir projeye yeni sözdizimi eklediğinizde bu hatayı görürseniz önce go satırını kontrol edin.

Yerel bir modülü kullanmak: replace ve go mod tidy

Şimdi metin modülünü kullanan ikinci bir modül yazalım. uygulama dizininde go mod init example.com/uygulama çalıştırıp şu main.go dosyasını ekliyoruz:

go
package main

import (
	"fmt"

	"example.com/metin"
)

func main() {
	fmt.Println(metin.Selamla("  Ayşe "))
}

Program bu hâliyle derlenmez; çünkü go.mod dosyasında example.com/metin için bir require satırı yoktur ve bu yol internette de bulunmaz:

text
main.go:6:2: no required module provides package example.com/metin; to add it:
	go get example.com/metin

Henüz yayımlanmamış bir modülü denemek için Managing dependencies belgesinin önerdiği yol, replace ile modül yolunu yerel dizine yönlendirmektir. Ardından go mod tidy eksik require satırını ekler:

bash
$ go mod edit -replace example.com/metin=../metin
$ go mod tidy
go: found example.com/metin in example.com/metin v0.0.0-00010101000000-000000000000
$ go run .
Merhaba, Ayşe!

İşlemden sonra go.mod şu hâle gelir:

text
module example.com/uygulama

go 1.27.3

replace example.com/metin => ../metin

require example.com/metin v0.0.0-00010101000000-000000000000

v0.0.0-00010101000000-000000000000 bir sözde sürümdür (pseudo-version). Go, etiketlenmiş bir sürümü olmayan modüller için bu biçimde sürüm üretir; yerel replace hedefinin gerçek bir sürümü olmadığından burada sıfır tarihli bir değer kullanıldı. Dikkat edilmesi gereken nokta şudur: go.mod referansına göre replace tek başına modülü modül grafiğine eklemez, ona işaret eden bir require satırı da gerekir. go mod tidy bu satırı sizin için yazar.

Klasöre baktığınızda go.sum dosyası oluşmadığını görürsünüz. Bu bir hata değildir: Go Modules Reference, tüm bağımlılıklar yerel dizinlere yönlendirildiğinde ya da hiç bağımlılık olmadığında go.sum dosyasının boş olabileceğini veya hiç bulunmayabileceğini belirtir.

go mod tidy tam olarak ne yapar?

go mod tidy, go.mod dosyasını kaynak koddaki gerçek ihtiyaçla eşitler. Ana modüldeki tüm paketleri, araçları ve bunların içe aktardığı paketleri testler dahil özyinelemeli olarak yükler; paket sağlayan her modül için bir require satırı olduğundan emin olur ve hiçbir ilgili paket sağlamayan modüllerin satırlarını siler. go.sum dosyasındaki eksik özetleri ekler, gereksizleri temizler. Belgede belirtilen önemli bir ayrıntı: tidy tüm derleme etiketleri etkinmiş gibi davranır, yani yalnızca Linux'ta derlenen bir dosyanın bağımlılığı da Windows'ta çalıştırdığınız tidy tarafından korunur. Tek istisna ignore etiketidir.

Bunu görmek için main.go dosyasından metin paketinin kullanımını kaldıralım. -diff bayrağı dosyaya dokunmadan yapılacak değişikliği gösterir ve fark varsa sıfırdan farklı bir çıkış koduyla biter; bu davranış CI hatlarında "go.mod güncel mi?" denetimi için kullanışlıdır. -v ise silinen modülleri standart hataya yazar:

bash
$ go mod tidy -diff
diff current/go.mod tidy/go.mod
--- current/go.mod
+++ tidy/go.mod
@@ -3,5 +3,3 @@
 go 1.27.3
 
 replace example.com/metin => ../metin
-
-require example.com/metin v0.0.0-00010101000000-000000000000
$ echo $?
1
$ go mod tidy -v
unused example.com/metin

require satırı silindi ama replace yerinde kaldı; tidy değiştirme yönergelerine dokunmaz. Go 1.27 sürüm notlarına göre go satırı 1.27 veya üstü olan modüllerde go mod tidy artık dağınık require bloklarını birleştirir ve dosyada en fazla iki blok bırakır: biri doğrudan, biri dolaylı bağımlılıklar için. Önceden elle düzenleme ya da birleştirme çakışmaları sonucu oluşan fazla bloklar olduğu gibi kalıyordu.

Sürüm seçimi: Minimal Version Selection

Go modül sürümleri v harfiyle başlayan anlamsal sürümlerdir: v1.4.2 gibi büyük, küçük ve yama numaralarından oluşur. Geriye uyumsuz bir değişiklikte büyük sürüm artar; v0 ile başlayan ya da -beta gibi ön sürüm eki taşıyan sürümler kararsız kabul edilir ve uyumluluk sözü vermez. v2 ve sonrasında modül yolunun sonuna /v2 eklenmesi gerekir; böylece aynı yapıda bir paketin iki uyumsuz büyük sürümü ayrı modüller olarak birlikte kullanılabilir.

Birden çok bağımlılık aynı modülün farklı sürümlerini istediğinde Go, Minimal Version Selection (MVS) algoritmasını kullanır. require satırlarındaki sürümler "en az bu sürüm" anlamına gelir. MVS ana modülden başlayıp grafiği dolaşır ve her modül için istenen en yüksek sürümü seçer; daha yeni bir sürüm yayımlanmış olsa bile kimse istemediyse onu seçmez. Bu yüzden derleme listesi bir kilit dosyasına kaydedilmez: algoritma deterministiktir ve yeni sürümler çıktığında sonuç kendiliğinden değişmez. Seçilen listeyi go list -m all ile görebilirsiniz:

bash
$ go list -m all
example.com/uygulama
example.com/metin v0.0.0-00010101000000-000000000000 => ../metin
$ go mod graph
example.com/uygulama example.com/metin@v0.0.0-00010101000000-000000000000
example.com/uygulama go@1.27.3
example.com/metin@v0.0.0-00010101000000-000000000000 go@1.27.3
go@1.27.3 toolchain@go1.27.3
$ go mod why example.com/metin
# example.com/metin
example.com/uygulama
example.com/metin

go mod graph gereksinim grafiğinin kenarlarını, go mod why ise bir paketin neden derlemeye girdiğini gösteren içe aktarma zincirini yazar. Büyük projelerde "bu bağımlılık nereden geliyor?" sorusunun cevabı genellikle bu iki komuttadır.

go get ile sürüm eklemek, yükseltmek, kaldırmak

Yayımlanmış bir modüle bağımlılık eklemek ya da sürümünü değiştirmek için go get kullanılır. Go Modules Reference'taki örnekler başlıca kalıpları gösterir:

bash
$ go get golang.org/x/net              # sürüm yazılmazsa @upgrade sorgusu kullanılır
$ go get -u ./...                      # içe aktarılan paketleri sağlayan modülleri yükseltir
$ go get golang.org/x/text@v0.3.2      # belirli bir sürüme yükseltir ya da düşürür
$ go get golang.org/x/text@none        # bağımlılığı kaldırır
$ go get go                            # go satırını yükseltir

go get, adı verilen modülün yeni sürümü başka modüllerin daha yüksek sürümünü gerektiriyorsa onları da yükseltir; bir modülü düşürdüğünüzde ona bağlı modüller de gerekirse düşürülür. -u=patch yalnızca yama sürümlerine yükseltir. Belgeye göre go get ile paket derleyip kurmak Go 1.17'de kullanımdan kaldırıldı ve Go 1.18'den beri -d davranışı hep etkindir: komut yalnızca go.mod dosyasındaki bağımlılıkları yönetir. Bir programı derleyip kurmak için Go 1.16'dan beri go install önerilir. Bu yazıdaki ortamda ağ erişimi olmadığı için bu komutların çıktısı gösterilmedi.

Go 1.24 ile gelen tool yönergesi, stringer gibi geliştirme araçlarını da modül bağımlılığı olarak izlemenizi sağlar: go get -tool golang.org/x/tools/cmd/stringer komutu hem tool hem require satırını ekler, ardından aracı go tool stringer ile çalıştırırsınız. Böylece eskiden kullanılan boş import içeren tools.go dosyasına gerek kalmaz.

go.sum dosyası neyi korur?

go.sum dosyası neyi korur? Modül yolu, Sürüm, Özet

go.sum, modülün doğrudan ve dolaylı bağımlılıklarının kriptografik özetlerini tutar. go komutu bir modülün .mod veya .zip dosyasını modül önbelleğine indirdiğinde özetini hesaplar ve ana modülün go.sum dosyasındaki kayıtla karşılaştırır; eşleşmezse durur. Her satır boşlukla ayrılmış üç alandan oluşur:

  • Modül yolu: özetin ait olduğu modül.
  • Sürüm: /go.mod ile bitiyorsa özet yalnızca o sürümün go.mod dosyasına aittir; bitmiyorsa modülün zip içeriğine.
  • Özet: h1: ile başlayan, base64 kodlu bir SHA-256 değeri. Belgeye göre şu an desteklenen tek algoritma h1'dir.

Bir dosyada aynı modülün birden çok sürümü bulunabilir, çünkü MVS hesap yaparken eski sürümlerin go.mod dosyalarını da okur. Yükseltmeden sonra artık gerekmeyen satırları go mod tidy temizler. Herkese açık modüller için ayrıca sum.golang.org üzerinde çalışan bir sağlama toplamı veritabanı vardır; bu sayede bir vekil sunucu ya da depo sahibi aynı sürümün içeriğini sonradan değiştirse bile fark edilir. Özel modüllerinizi bu veritabanına ve genel vekile sormamak için GOPRIVATE ortam değişkenine modül yolu desenlerinizi yazarsınız; bu değişken GONOPROXY ve GONOSUMDB için varsayılan değer olur.

İndirilen modüller $GOPATH/pkg/mod altındaki modül önbelleğinde salt okunur izinlerle saklanır, bu yüzden rm -rf ile silmek zordur; önbelleği go clean -modcache ile temizlersiniz. Önbellekteki dosyaların indirildikten sonra değişip değişmediğini go mod verify denetler; bu örnekte tüm bağımlılık yerel olduğu için çıktı yalnızca all modules verified oldu.

Çok modüllü çalışma alanı: go work

Birbirine bağlı birkaç modülü aynı anda geliştiriyorsanız her birine replace yazmak yerine Go 1.18 ile gelen çalışma alanı (workspace) kipini kullanabilirsiniz. Üst dizinde go work init bir go.work dosyası oluşturur ve use satırlarındaki modüller birlikte ana modül gibi davranır. Aynı iki modülü bu kez replace olmadan, bir çalışma alanında denedik:

bash
$ go work init ./metin ./uygulama
$ cat go.work
go 1.27.3

use (
	./metin
	./uygulama
)
$ go run ./uygulama
Merhaba, Ayşe!

go komutu çalışma alanı kipinde olup olmadığını GOWORK ortam değişkenine ve üst dizinlerde bir go.work dosyası bulunup bulunmadığına bakarak belirler; GOWORK=off bu kipi kapatır, go env GOWORK hangi dosyanın kullanıldığını gösterir. Belgeye göre go mod tidy, go mod why, go mod edit ve go get çalışma alanında da her zaman tek bir ana modül üzerinde çalışır. Çalışma alanlarının tüm akışı için Tutorial: Getting started with multi-module workspaces sayfasına bakabilirsiniz.

Sık yapılan hatalar

  • Modül yolunu rastgele seçmek: app ya da utils gibi genel adlar başka modüllerle çakışabilir. Belge, depo yolunu ya da size ait bir ön eki önerir.
  • replace satırını bağımlılara da etkili sanmak: replace ve exclude yalnızca ana modülde uygulanır; yayımladığınız bir kütüphanede yerel replace bırakmak onu kullananları etkilemez ama kendi CI ortamınızı bozabilir.
  • replace ekleyip require eklememek: Değiştirme tek başına modülü grafiğe almaz; go mod tidy çalıştırın.
  • go.sum dosyasını depoya koymamak: Özetler olmadan başka bir makinede doğrulama yapılamaz.
  • go satırını gereğinden yüksek tutmak: Kütüphanenizi kullananlar en az o sürüme geçmek zorunda kalır. Gerçekten kullandığınız en yeni dil ve kütüphane özelliğine göre ayarlayın.
  • v2 çıkarırken yolu değiştirmemek: Büyük sürüm eki kuralına göre v2.0.0 ve sonrasında modül yolu /v2 gibi bir ekle bitmelidir; bu ek, uyumsuz büyük sürümlere ayrı import yolları verir.

Sık Sorulan Sorular

go.mod ve go.sum dosyalarını Git'e eklemeli miyim?

Evet. go.mod modülün kimliğini ve bağımlılıklarını, go.sum ise bunların doğrulama özetlerini taşır. İkisi birlikte olmadan aynı derlemeyi başka bir makinede güvenilir biçimde tekrarlayamazsınız. go.work ise çoğunlukla yerel bir tercihtir.

Go'da package-lock gibi bir kilit dosyası neden yok?

Minimal Version Selection deterministik olduğu için: derleme listesi her komutta go.mod dosyalarından yeniden hesaplanır ve yeni sürümlerin yayımlanması sonucu değiştirmez. Sürümü siz go get ile yükseltmediğiniz sürece seçim aynı kalır.

go mod tidy ile go get arasındaki fark nedir?

go get belirli bir modülü ekler, yükseltir, düşürür veya kaldırır; yani bir niyeti uygular. go mod tidy ise belirli bir modülle ilgilenmez, kaynak koda bakıp go.mod ve go.sum dosyalarını eksiksiz ve fazlasız hâle getirir. Kod değiştikten sonra tidy, sürüm değiştirmek istediğinizde get kullanılır.

// indirect yorumu ne anlama gelir?

// indirect, ana modüldeki hiçbir paketin doğrudan içe aktarmadığı ama derleme için gereken bir modülü işaretler. Go 1.17 ve sonrasını hedefleyen modüllerde bu tür dolaylı bağımlılıklar da açıkça listelenir ve ayrı bir blokta tutulur; bu bilgi modül grafiğinin budanmasını ve tembel yüklemeyi mümkün kılar.

Modülümü nasıl test ederim?

Modül içindeki her paket için go test ./... çalıştırabilirsiniz. Test dosyalarının yazımı Go test yazma rehberi yazısında, modülün derlenip ikili dosyaya dönüştürülmesi ise go build ve çapraz derleme yazısında anlatılıyor.

Marka adları sahiplerine aittir. Bu yazı bağımsız bir teknik rehberdir; adı geçen kuruluşlarla bayilik veya ortaklık ilişkisi bulunduğu anlamına gelmez.

İlgili içerikler: Go öğrenme rehberi · Go paket yapısı ve import · go build ve çapraz derleme · Go test yazma · gofmt, go vet ve go doc · Go nedir?