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:
$ 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.3Oluş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:
// 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 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önerge | Ne yapar | Not |
|---|---|---|
| module | Modül yolunu bildirir | v2 ve sonrası için yol /v2 gibi bir ekle biter |
| go | Gereken 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 |
| godebug | Varsayılan GODEBUG ayarları | Yalnızca ana modülün main paketlerine uygulanır |
| require | Bir bağımlılığın en düşük sürümü | go get ve go mod tidy yönetir |
| tool | Go ile yazılmış geliştirici aracı | Go 1.24 ile geldi, go tool ile çalışır |
| replace | Bir modülü başka sürüm ya da yerel dizinle değiştirir | Yalnızca ana modülde uygulanır |
| exclude | Belirli bir sürümü dışlar | Yalnızca ana modülde uygulanır |
| retract | Yayımlanmış kendi sürümünüzü geri çeker | Modülün en son sürümünden okunur |
| ignore | Desen eşleşmesinde dizinleri yok sayar | Go 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.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:
$ 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:
package main
import "fmt"
func main() {
for i := range 3 {
fmt.Println(i)
}
}# 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:
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:
main.go:6:2: no required module provides package example.com/metin; to add it:
go get example.com/metinHenü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:
$ 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:
module example.com/uygulama
go 1.27.3
replace example.com/metin => ../metin
require example.com/metin v0.0.0-00010101000000-000000000000v0.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:
$ 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/metinrequire 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:
$ 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/metingo 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:
$ 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ükseltirgo 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, 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.modile bitiyorsa özet yalnızca o sürümüngo.moddosyası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 algoritmah1'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:
$ 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:
appya dautilsgibi 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:
replaceveexcludeyalnızca ana modülde uygulanır; yayımladığınız bir kütüphanede yerelreplacebı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.0ve sonrasında modül yolu/v2gibi 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?