[{"data":1,"prerenderedAt":1319},["ShallowReactive",2],{"page-\u002Fgo\u002F21-packages-and-modules":3},{"id":4,"title":5,"body":6,"description":1312,"extension":1313,"meta":1314,"navigation":99,"path":1315,"seo":1316,"stem":1317,"__hash__":1318},"content\u002Fgo\u002F21-packages-and-modules.md","21 — Packages & Modules",{"type":7,"value":8,"toc":1306},"minimark",[9,13,18,1244,1285,1289,1302],[10,11,5],"h1",{"id":12},"_21-packages-modules",[14,15,17],"h2",{"id":16},"package-organization","Package Organization",[19,20,22,167,175],"code-wrapper",{"language":21},"go",[23,24,28],"pre",{"className":25,"code":26,"language":21,"meta":27,"style":27},"language-go shiki shiki-themes github-light github-dark","\u002F\u002F ┌──────────────────────────────────────────────────────────────────────┐\n\u002F\u002F │ Package  = directory of .go files with the same `package` clause     │\n\u002F\u002F │ Module   = versioned collection of packages, defined by go.mod      │\n\u002F\u002F │ Import   = module path + subdirectory path                           │\n\u002F\u002F │                                                                      │\n\u002F\u002F │ Visibility:                                                          │\n\u002F\u002F │   PascalCase = exported (public)                                     │\n\u002F\u002F │   camelCase  = unexported (package-private)                          │\n\u002F\u002F │   internal\u002F  = toolchain-enforced private (only within parent)       │\n\u002F\u002F └──────────────────────────────────────────────────────────────────────┘\n\n\u002F\u002F File structure:\n\u002F\u002F   example.com\u002Fmyapp\u002F\n\u002F\u002F   ├── go.mod                      # module example.com\u002Fmyapp\n\u002F\u002F   ├── go.sum                      # dependency hashes\n\u002F\u002F   ├── cmd\u002Fmyapp\u002Fmain.go           # package main — entry point\n\u002F\u002F   ├── internal\u002F\n\u002F\u002F   │   ├── config\u002Fconfig.go        # package config — private to myapp\n\u002F\u002F   │   ├── domain\u002Fuser.go           # package domain — business types\n\u002F\u002F   │   └── store\u002Fpostgres\u002F         # package postgres — DB impl\n\u002F\u002F   └── pkg\u002F\n\u002F\u002F       └── ratelimiter\u002F            # package ratelimiter — public, reusable\n","",[29,30,31,40,46,52,58,64,70,76,82,88,94,101,107,113,119,125,131,137,143,149,155,161],"code",{"__ignoreMap":27},[32,33,36],"span",{"class":34,"line":35},"line",1,[32,37,39],{"class":38},"sdCPZ","\u002F\u002F ┌──────────────────────────────────────────────────────────────────────┐\n",[32,41,43],{"class":34,"line":42},2,[32,44,45],{"class":38},"\u002F\u002F │ Package  = directory of .go files with the same `package` clause     │\n",[32,47,49],{"class":34,"line":48},3,[32,50,51],{"class":38},"\u002F\u002F │ Module   = versioned collection of packages, defined by go.mod      │\n",[32,53,55],{"class":34,"line":54},4,[32,56,57],{"class":38},"\u002F\u002F │ Import   = module path + subdirectory path                           │\n",[32,59,61],{"class":34,"line":60},5,[32,62,63],{"class":38},"\u002F\u002F │                                                                      │\n",[32,65,67],{"class":34,"line":66},6,[32,68,69],{"class":38},"\u002F\u002F │ Visibility:                                                          │\n",[32,71,73],{"class":34,"line":72},7,[32,74,75],{"class":38},"\u002F\u002F │   PascalCase = exported (public)                                     │\n",[32,77,79],{"class":34,"line":78},8,[32,80,81],{"class":38},"\u002F\u002F │   camelCase  = unexported (package-private)                          │\n",[32,83,85],{"class":34,"line":84},9,[32,86,87],{"class":38},"\u002F\u002F │   internal\u002F  = toolchain-enforced private (only within parent)       │\n",[32,89,91],{"class":34,"line":90},10,[32,92,93],{"class":38},"\u002F\u002F └──────────────────────────────────────────────────────────────────────┘\n",[32,95,97],{"class":34,"line":96},11,[32,98,100],{"emptyLinePlaceholder":99},true,"\n",[32,102,104],{"class":34,"line":103},12,[32,105,106],{"class":38},"\u002F\u002F File structure:\n",[32,108,110],{"class":34,"line":109},13,[32,111,112],{"class":38},"\u002F\u002F   example.com\u002Fmyapp\u002F\n",[32,114,116],{"class":34,"line":115},14,[32,117,118],{"class":38},"\u002F\u002F   ├── go.mod                      # module example.com\u002Fmyapp\n",[32,120,122],{"class":34,"line":121},15,[32,123,124],{"class":38},"\u002F\u002F   ├── go.sum                      # dependency hashes\n",[32,126,128],{"class":34,"line":127},16,[32,129,130],{"class":38},"\u002F\u002F   ├── cmd\u002Fmyapp\u002Fmain.go           # package main — entry point\n",[32,132,134],{"class":34,"line":133},17,[32,135,136],{"class":38},"\u002F\u002F   ├── internal\u002F\n",[32,138,140],{"class":34,"line":139},18,[32,141,142],{"class":38},"\u002F\u002F   │   ├── config\u002Fconfig.go        # package config — private to myapp\n",[32,144,146],{"class":34,"line":145},19,[32,147,148],{"class":38},"\u002F\u002F   │   ├── domain\u002Fuser.go           # package domain — business types\n",[32,150,152],{"class":34,"line":151},20,[32,153,154],{"class":38},"\u002F\u002F   │   └── store\u002Fpostgres\u002F         # package postgres — DB impl\n",[32,156,158],{"class":34,"line":157},21,[32,159,160],{"class":38},"\u002F\u002F   └── pkg\u002F\n",[32,162,164],{"class":34,"line":163},22,[32,165,166],{"class":38},"\u002F\u002F       └── ratelimiter\u002F            # package ratelimiter — public, reusable\n",[14,168,170,171,174],{"id":169},"the-internal-enforcement","The ",[29,172,173],{},"internal\u002F"," Enforcement",[19,176,177,272,276],{"language":21},[23,178,180],{"className":25,"code":179,"language":21,"meta":27,"style":27},"\u002F\u002F Packages under internal\u002F can ONLY be imported by code within the\n\u002F\u002F parent of internal\u002F. The Go TOOLCHAIN enforces this at compile time.\n\n\u002F\u002F example.com\u002Fmyapp\u002Finternal\u002Fconfig\u002Fconfig.go\npackage config\n\ntype Config struct {\n    DSN string\n}\n\n\u002F\u002F This can be imported by:\n\u002F\u002F   ✅ example.com\u002Fmyapp\u002Fcmd\u002Fmyapp\u002Fmain.go\n\u002F\u002F   ✅ example.com\u002Fmyapp\u002Finternal\u002Fstore\u002Fstore.go\n\u002F\u002F   ❌ example.com\u002Fother-app\u002Fmain.go  — compile error: \"use of internal package not allowed\"\n\u002F\u002F   ❌ github.com\u002Fsome\u002Flib\u002Flib.go      — compile error\n",[29,181,182,187,192,196,201,211,215,230,238,243,247,252,257,262,267],{"__ignoreMap":27},[32,183,184],{"class":34,"line":35},[32,185,186],{"class":38},"\u002F\u002F Packages under internal\u002F can ONLY be imported by code within the\n",[32,188,189],{"class":34,"line":42},[32,190,191],{"class":38},"\u002F\u002F parent of internal\u002F. The Go TOOLCHAIN enforces this at compile time.\n",[32,193,194],{"class":34,"line":48},[32,195,100],{"emptyLinePlaceholder":99},[32,197,198],{"class":34,"line":54},[32,199,200],{"class":38},"\u002F\u002F example.com\u002Fmyapp\u002Finternal\u002Fconfig\u002Fconfig.go\n",[32,202,203,207],{"class":34,"line":60},[32,204,206],{"class":205},"svdQ7","package",[32,208,210],{"class":209},"sIsaT"," config\n",[32,212,213],{"class":34,"line":66},[32,214,100],{"emptyLinePlaceholder":99},[32,216,217,220,223,226],{"class":34,"line":72},[32,218,219],{"class":205},"type",[32,221,222],{"class":209}," Config",[32,224,225],{"class":205}," struct",[32,227,229],{"class":228},"ssxIu"," {\n",[32,231,232,235],{"class":34,"line":78},[32,233,234],{"class":228},"    DSN ",[32,236,237],{"class":205},"string\n",[32,239,240],{"class":34,"line":84},[32,241,242],{"class":228},"}\n",[32,244,245],{"class":34,"line":90},[32,246,100],{"emptyLinePlaceholder":99},[32,248,249],{"class":34,"line":96},[32,250,251],{"class":38},"\u002F\u002F This can be imported by:\n",[32,253,254],{"class":34,"line":103},[32,255,256],{"class":38},"\u002F\u002F   ✅ example.com\u002Fmyapp\u002Fcmd\u002Fmyapp\u002Fmain.go\n",[32,258,259],{"class":34,"line":109},[32,260,261],{"class":38},"\u002F\u002F   ✅ example.com\u002Fmyapp\u002Finternal\u002Fstore\u002Fstore.go\n",[32,263,264],{"class":34,"line":115},[32,265,266],{"class":38},"\u002F\u002F   ❌ example.com\u002Fother-app\u002Fmain.go  — compile error: \"use of internal package not allowed\"\n",[32,268,269],{"class":34,"line":121},[32,270,271],{"class":38},"\u002F\u002F   ❌ github.com\u002Fsome\u002Flib\u002Flib.go      — compile error\n",[14,273,275],{"id":274},"module-versioning-semantics","Module Versioning Semantics",[19,277,279,460,467],{"language":278},"bash",[23,280,283],{"className":281,"code":282,"language":278,"meta":27,"style":27},"language-bash shiki shiki-themes github-light github-dark","# Go uses Semantic Versioning: vMAJOR.MINOR.PATCH\n#   v1.2.3 → major=1, minor=2, patch=3\n#\n# Import paths for v2+ include the major version:\n#   v1: github.com\u002Flib\u002Fpq          → import \"github.com\u002Flib\u002Fpq\"\n#   v2: github.com\u002Ffoo\u002Fbar\u002Fv2      → import \"github.com\u002Ffoo\u002Fbar\u002Fv2\"\n#   v3: github.com\u002Ffoo\u002Fbar\u002Fv3      → import \"github.com\u002Ffoo\u002Fbar\u002Fv3\"\n#\n# v0.x and v1.x don't have a version suffix in the import path.\n# v2+ MUST have \u002Fv2, \u002Fv3, etc. in the module path and import path.\n\n# Add\u002Fupdate dependencies:\ngo get github.com\u002Flib\u002Fpq@latest           # latest stable\ngo get github.com\u002Flib\u002Fpq@v1.10.9           # exact version\ngo get github.com\u002Flib\u002Fpq@v1.10.0-beta.1    # pre-release\ngo get github.com\u002Fsome\u002Frepo@main           # ⚠️ pseudo-version (unstable)\n\n# Tidy — add missing, remove unused, update go.sum:\ngo mod tidy\n\n# Upgrade a dependency:\ngo get github.com\u002Flib\u002Fpq@latest\ngo mod tidy\n\n# Downgrade:\ngo get github.com\u002Flib\u002Fpq@v1.9.0\n",[29,284,285,290,295,300,305,310,315,320,324,329,334,338,343,357,369,381,393,397,402,412,416,421,430,439,444,450],{"__ignoreMap":27},[32,286,287],{"class":34,"line":35},[32,288,289],{"class":38},"# Go uses Semantic Versioning: vMAJOR.MINOR.PATCH\n",[32,291,292],{"class":34,"line":42},[32,293,294],{"class":38},"#   v1.2.3 → major=1, minor=2, patch=3\n",[32,296,297],{"class":34,"line":48},[32,298,299],{"class":38},"#\n",[32,301,302],{"class":34,"line":54},[32,303,304],{"class":38},"# Import paths for v2+ include the major version:\n",[32,306,307],{"class":34,"line":60},[32,308,309],{"class":38},"#   v1: github.com\u002Flib\u002Fpq          → import \"github.com\u002Flib\u002Fpq\"\n",[32,311,312],{"class":34,"line":66},[32,313,314],{"class":38},"#   v2: github.com\u002Ffoo\u002Fbar\u002Fv2      → import \"github.com\u002Ffoo\u002Fbar\u002Fv2\"\n",[32,316,317],{"class":34,"line":72},[32,318,319],{"class":38},"#   v3: github.com\u002Ffoo\u002Fbar\u002Fv3      → import \"github.com\u002Ffoo\u002Fbar\u002Fv3\"\n",[32,321,322],{"class":34,"line":78},[32,323,299],{"class":38},[32,325,326],{"class":34,"line":84},[32,327,328],{"class":38},"# v0.x and v1.x don't have a version suffix in the import path.\n",[32,330,331],{"class":34,"line":90},[32,332,333],{"class":38},"# v2+ MUST have \u002Fv2, \u002Fv3, etc. in the module path and import path.\n",[32,335,336],{"class":34,"line":96},[32,337,100],{"emptyLinePlaceholder":99},[32,339,340],{"class":34,"line":103},[32,341,342],{"class":38},"# Add\u002Fupdate dependencies:\n",[32,344,345,347,351,354],{"class":34,"line":109},[32,346,21],{"class":209},[32,348,350],{"class":349},"sJ6F3"," get",[32,352,353],{"class":349}," github.com\u002Flib\u002Fpq@latest",[32,355,356],{"class":38},"           # latest stable\n",[32,358,359,361,363,366],{"class":34,"line":115},[32,360,21],{"class":209},[32,362,350],{"class":349},[32,364,365],{"class":349}," github.com\u002Flib\u002Fpq@v1.10.9",[32,367,368],{"class":38},"           # exact version\n",[32,370,371,373,375,378],{"class":34,"line":121},[32,372,21],{"class":209},[32,374,350],{"class":349},[32,376,377],{"class":349}," github.com\u002Flib\u002Fpq@v1.10.0-beta.1",[32,379,380],{"class":38},"    # pre-release\n",[32,382,383,385,387,390],{"class":34,"line":127},[32,384,21],{"class":209},[32,386,350],{"class":349},[32,388,389],{"class":349}," github.com\u002Fsome\u002Frepo@main",[32,391,392],{"class":38},"           # ⚠️ pseudo-version (unstable)\n",[32,394,395],{"class":34,"line":133},[32,396,100],{"emptyLinePlaceholder":99},[32,398,399],{"class":34,"line":139},[32,400,401],{"class":38},"# Tidy — add missing, remove unused, update go.sum:\n",[32,403,404,406,409],{"class":34,"line":145},[32,405,21],{"class":209},[32,407,408],{"class":349}," mod",[32,410,411],{"class":349}," tidy\n",[32,413,414],{"class":34,"line":151},[32,415,100],{"emptyLinePlaceholder":99},[32,417,418],{"class":34,"line":157},[32,419,420],{"class":38},"# Upgrade a dependency:\n",[32,422,423,425,427],{"class":34,"line":163},[32,424,21],{"class":209},[32,426,350],{"class":349},[32,428,429],{"class":349}," github.com\u002Flib\u002Fpq@latest\n",[32,431,433,435,437],{"class":34,"line":432},23,[32,434,21],{"class":209},[32,436,408],{"class":349},[32,438,411],{"class":349},[32,440,442],{"class":34,"line":441},24,[32,443,100],{"emptyLinePlaceholder":99},[32,445,447],{"class":34,"line":446},25,[32,448,449],{"class":38},"# Downgrade:\n",[32,451,453,455,457],{"class":34,"line":452},26,[32,454,21],{"class":209},[32,456,350],{"class":349},[32,458,459],{"class":349}," github.com\u002Flib\u002Fpq@v1.9.0\n",[14,461,463,466],{"id":462},"replace-directives-local-development",[29,464,465],{},"replace"," Directives — Local Development",[19,468,469,551,555],{"language":21},[23,470,472],{"className":25,"code":471,"language":21,"meta":27,"style":27},"\u002F\u002F go.mod:\n\u002F\u002F   replace example.com\u002Fmylib => ..\u002Fmylib\n\u002F\u002F   replace github.com\u002Flib\u002Fpq => github.com\u002Fmyfork\u002Fpq v1.10.1\n\n\u002F\u002F ❌ ANTI-PATTERN: using replace in a PUBLISHED library's go.mod\n\u002F\u002F Consumers inherit the replace — breaks if they don't have the local path.\n\u002F\u002F Never commit replace directives in library go.mod files.\n\n\u002F\u002F ✅ CORRECT: use go.work for local dev (gitignored)\n\u002F\u002F go.work (developer-local):\n\u002F\u002F   use .\u002Fmyapp\n\u002F\u002F   use ..\u002Fmylib\n\u002F\u002F go.mod stays clean (no replace) for CI and publishing.\n\n\u002F\u002F ✅ Legitimate replace: security fork in an APPLICATION (not library):\n\u002F\u002F   replace github.com\u002Fvulnerable\u002Fdep => github.com\u002Fpatched\u002Fdep v1.2.1\n",[29,473,474,479,484,489,493,498,503,508,512,517,522,527,532,537,541,546],{"__ignoreMap":27},[32,475,476],{"class":34,"line":35},[32,477,478],{"class":38},"\u002F\u002F go.mod:\n",[32,480,481],{"class":34,"line":42},[32,482,483],{"class":38},"\u002F\u002F   replace example.com\u002Fmylib => ..\u002Fmylib\n",[32,485,486],{"class":34,"line":48},[32,487,488],{"class":38},"\u002F\u002F   replace github.com\u002Flib\u002Fpq => github.com\u002Fmyfork\u002Fpq v1.10.1\n",[32,490,491],{"class":34,"line":54},[32,492,100],{"emptyLinePlaceholder":99},[32,494,495],{"class":34,"line":60},[32,496,497],{"class":38},"\u002F\u002F ❌ ANTI-PATTERN: using replace in a PUBLISHED library's go.mod\n",[32,499,500],{"class":34,"line":66},[32,501,502],{"class":38},"\u002F\u002F Consumers inherit the replace — breaks if they don't have the local path.\n",[32,504,505],{"class":34,"line":72},[32,506,507],{"class":38},"\u002F\u002F Never commit replace directives in library go.mod files.\n",[32,509,510],{"class":34,"line":78},[32,511,100],{"emptyLinePlaceholder":99},[32,513,514],{"class":34,"line":84},[32,515,516],{"class":38},"\u002F\u002F ✅ CORRECT: use go.work for local dev (gitignored)\n",[32,518,519],{"class":34,"line":90},[32,520,521],{"class":38},"\u002F\u002F go.work (developer-local):\n",[32,523,524],{"class":34,"line":96},[32,525,526],{"class":38},"\u002F\u002F   use .\u002Fmyapp\n",[32,528,529],{"class":34,"line":103},[32,530,531],{"class":38},"\u002F\u002F   use ..\u002Fmylib\n",[32,533,534],{"class":34,"line":109},[32,535,536],{"class":38},"\u002F\u002F go.mod stays clean (no replace) for CI and publishing.\n",[32,538,539],{"class":34,"line":115},[32,540,100],{"emptyLinePlaceholder":99},[32,542,543],{"class":34,"line":121},[32,544,545],{"class":38},"\u002F\u002F ✅ Legitimate replace: security fork in an APPLICATION (not library):\n",[32,547,548],{"class":34,"line":127},[32,549,550],{"class":38},"\u002F\u002F   replace github.com\u002Fvulnerable\u002Fdep => github.com\u002Fpatched\u002Fdep v1.2.1\n",[14,552,554],{"id":553},"private-modules","Private Modules",[19,556,557,676,683],{"language":278},[23,558,560],{"className":281,"code":559,"language":278,"meta":27,"style":27},"# Private modules need GOPRIVATE so the Go tool doesn't try the public proxy:\ngo env -w GOPRIVATE=github.com\u002Fyourorg\u002F*\n\n# Or for a specific host:\ngo env -w GOPRIVATE=gitlab.com\u002Fyourcompany\u002F*\n\n# Without GOPRIVATE, `go get` from a private repo fails with 404\n# (the Go proxy can't access private repos).\n\n# Auth: configure git credentials:\n#   ~\u002F.netrc:\n#     machine github.com\n#     login your-token\n#     password ghp_xxxxx\n#   Or use SSH keys (go uses git for fetching).\n\n# GOINSECURE for self-hosted HTTP (no TLS):\ngo env -w GOINSECURE=internal.company.git\u002F*\n",[29,561,562,567,584,588,593,606,610,615,620,624,629,634,639,644,649,654,658,663],{"__ignoreMap":27},[32,563,564],{"class":34,"line":35},[32,565,566],{"class":38},"# Private modules need GOPRIVATE so the Go tool doesn't try the public proxy:\n",[32,568,569,571,574,578,581],{"class":34,"line":42},[32,570,21],{"class":209},[32,572,573],{"class":349}," env",[32,575,577],{"class":576},"snvgF"," -w",[32,579,580],{"class":349}," GOPRIVATE=github.com\u002Fyourorg\u002F",[32,582,583],{"class":576},"*\n",[32,585,586],{"class":34,"line":48},[32,587,100],{"emptyLinePlaceholder":99},[32,589,590],{"class":34,"line":54},[32,591,592],{"class":38},"# Or for a specific host:\n",[32,594,595,597,599,601,604],{"class":34,"line":60},[32,596,21],{"class":209},[32,598,573],{"class":349},[32,600,577],{"class":576},[32,602,603],{"class":349}," GOPRIVATE=gitlab.com\u002Fyourcompany\u002F",[32,605,583],{"class":576},[32,607,608],{"class":34,"line":66},[32,609,100],{"emptyLinePlaceholder":99},[32,611,612],{"class":34,"line":72},[32,613,614],{"class":38},"# Without GOPRIVATE, `go get` from a private repo fails with 404\n",[32,616,617],{"class":34,"line":78},[32,618,619],{"class":38},"# (the Go proxy can't access private repos).\n",[32,621,622],{"class":34,"line":84},[32,623,100],{"emptyLinePlaceholder":99},[32,625,626],{"class":34,"line":90},[32,627,628],{"class":38},"# Auth: configure git credentials:\n",[32,630,631],{"class":34,"line":96},[32,632,633],{"class":38},"#   ~\u002F.netrc:\n",[32,635,636],{"class":34,"line":103},[32,637,638],{"class":38},"#     machine github.com\n",[32,640,641],{"class":34,"line":109},[32,642,643],{"class":38},"#     login your-token\n",[32,645,646],{"class":34,"line":115},[32,647,648],{"class":38},"#     password ghp_xxxxx\n",[32,650,651],{"class":34,"line":121},[32,652,653],{"class":38},"#   Or use SSH keys (go uses git for fetching).\n",[32,655,656],{"class":34,"line":127},[32,657,100],{"emptyLinePlaceholder":99},[32,659,660],{"class":34,"line":133},[32,661,662],{"class":38},"# GOINSECURE for self-hosted HTTP (no TLS):\n",[32,664,665,667,669,671,674],{"class":34,"line":139},[32,666,21],{"class":209},[32,668,573],{"class":349},[32,670,577],{"class":576},[32,672,673],{"class":349}," GOINSECURE=internal.company.git\u002F",[32,675,583],{"class":576},[14,677,679,682],{"id":678},"gosum-supply-chain-verification",[29,680,681],{},"go.sum"," — Supply Chain Verification",[19,684,685,761,769],{"language":278},[23,686,688],{"className":281,"code":687,"language":278,"meta":27,"style":27},"# go.sum records SHA-256 hashes of every dependency's zip + go.mod.\n# The Go tool verifies these on download — if a registry serves a\n# different hash, the build FAILS. This is supply-chain protection.\n\n# Verify all cached modules match go.sum:\ngo mod verify\n\n# Why go.sum matters:\n#   1. Reproducibility — same go.sum → same dependencies\n#   2. Security — tampered dependencies fail to build\n#   3. Auditing — you can see exactly what versions were used\n\n# ⚠️ go.sum should be COMMITTED to version control.\n# go.mod and go.sum together define the build — both must be in git.\n",[29,689,690,695,700,705,709,714,723,727,732,737,742,747,751,756],{"__ignoreMap":27},[32,691,692],{"class":34,"line":35},[32,693,694],{"class":38},"# go.sum records SHA-256 hashes of every dependency's zip + go.mod.\n",[32,696,697],{"class":34,"line":42},[32,698,699],{"class":38},"# The Go tool verifies these on download — if a registry serves a\n",[32,701,702],{"class":34,"line":48},[32,703,704],{"class":38},"# different hash, the build FAILS. This is supply-chain protection.\n",[32,706,707],{"class":34,"line":54},[32,708,100],{"emptyLinePlaceholder":99},[32,710,711],{"class":34,"line":60},[32,712,713],{"class":38},"# Verify all cached modules match go.sum:\n",[32,715,716,718,720],{"class":34,"line":66},[32,717,21],{"class":209},[32,719,408],{"class":349},[32,721,722],{"class":349}," verify\n",[32,724,725],{"class":34,"line":72},[32,726,100],{"emptyLinePlaceholder":99},[32,728,729],{"class":34,"line":78},[32,730,731],{"class":38},"# Why go.sum matters:\n",[32,733,734],{"class":34,"line":84},[32,735,736],{"class":38},"#   1. Reproducibility — same go.sum → same dependencies\n",[32,738,739],{"class":34,"line":90},[32,740,741],{"class":38},"#   2. Security — tampered dependencies fail to build\n",[32,743,744],{"class":34,"line":96},[32,745,746],{"class":38},"#   3. Auditing — you can see exactly what versions were used\n",[32,748,749],{"class":34,"line":103},[32,750,100],{"emptyLinePlaceholder":99},[32,752,753],{"class":34,"line":109},[32,754,755],{"class":38},"# ⚠️ go.sum should be COMMITTED to version control.\n",[32,757,758],{"class":34,"line":115},[32,759,760],{"class":38},"# go.mod and go.sum together define the build — both must be in git.\n",[14,762,764,765,768],{"id":763},"workspaces-go-work","Workspaces (",[29,766,767],{},"go work",")",[19,770,771,880,884],{"language":278},[23,772,774],{"className":281,"code":773,"language":278,"meta":27,"style":27},"# go work lets you develop multiple modules simultaneously, with local\n# edits taking effect without replace directives.\n\nmkdir workspace && cd workspace\ngo work init .\u002Fmyapp .\u002Flib\u002Fmylib\n# go.work:\n#   go 1.22\n#   use .\u002Fmyapp\n#   use .\u002Flib\u002Fmylib\n\n# Now `go build` in .\u002Fmyapp resolves imports of example.com\u002Fmylib\n# to the LOCAL .\u002Flib\u002Fmylib — no replace directive needed.\n# go.work is developer-local — gitignore it (don't commit).\n\n# Sync go.work module versions back to go.mod:\ngo work sync\n",[29,775,776,781,786,790,807,823,828,833,838,843,847,852,857,862,866,871],{"__ignoreMap":27},[32,777,778],{"class":34,"line":35},[32,779,780],{"class":38},"# go work lets you develop multiple modules simultaneously, with local\n",[32,782,783],{"class":34,"line":42},[32,784,785],{"class":38},"# edits taking effect without replace directives.\n",[32,787,788],{"class":34,"line":48},[32,789,100],{"emptyLinePlaceholder":99},[32,791,792,795,798,801,804],{"class":34,"line":54},[32,793,794],{"class":209},"mkdir",[32,796,797],{"class":349}," workspace",[32,799,800],{"class":228}," && ",[32,802,803],{"class":576},"cd",[32,805,806],{"class":349}," workspace\n",[32,808,809,811,814,817,820],{"class":34,"line":60},[32,810,21],{"class":209},[32,812,813],{"class":349}," work",[32,815,816],{"class":349}," init",[32,818,819],{"class":349}," .\u002Fmyapp",[32,821,822],{"class":349}," .\u002Flib\u002Fmylib\n",[32,824,825],{"class":34,"line":66},[32,826,827],{"class":38},"# go.work:\n",[32,829,830],{"class":34,"line":72},[32,831,832],{"class":38},"#   go 1.22\n",[32,834,835],{"class":34,"line":78},[32,836,837],{"class":38},"#   use .\u002Fmyapp\n",[32,839,840],{"class":34,"line":84},[32,841,842],{"class":38},"#   use .\u002Flib\u002Fmylib\n",[32,844,845],{"class":34,"line":90},[32,846,100],{"emptyLinePlaceholder":99},[32,848,849],{"class":34,"line":96},[32,850,851],{"class":38},"# Now `go build` in .\u002Fmyapp resolves imports of example.com\u002Fmylib\n",[32,853,854],{"class":34,"line":103},[32,855,856],{"class":38},"# to the LOCAL .\u002Flib\u002Fmylib — no replace directive needed.\n",[32,858,859],{"class":34,"line":109},[32,860,861],{"class":38},"# go.work is developer-local — gitignore it (don't commit).\n",[32,863,864],{"class":34,"line":115},[32,865,100],{"emptyLinePlaceholder":99},[32,867,868],{"class":34,"line":121},[32,869,870],{"class":38},"# Sync go.work module versions back to go.mod:\n",[32,872,873,875,877],{"class":34,"line":127},[32,874,21],{"class":209},[32,876,813],{"class":349},[32,878,879],{"class":349}," sync\n",[14,881,883],{"id":882},"version-upgrades-breaking-changes","Version Upgrades — Breaking Changes",[19,885,886,1037,1041,1106,1110,1204,1208],{"language":278},[23,887,889],{"className":281,"code":888,"language":278,"meta":27,"style":27},"# Check for outdated dependencies:\ngo list -m -u all  # shows current and latest versions\n\n# Upgrade a single dependency:\ngo get github.com\u002Flib\u002Fpq@latest\ngo mod tidy\ngo test .\u002F...  # ⚠️ always test after upgrading\n\n# Upgrade ALL dependencies (careful — may break things):\ngo get -u .\u002F...\ngo mod tidy\ngo test .\u002F...\n\n# Major version upgrade (v1 → v2):\n#   1. Change the import path: \"github.com\u002Ffoo\u002Fbar\" → \"github.com\u002Ffoo\u002Fbar\u002Fv2\"\n#   2. go mod tidy\n#   3. Fix breaking API changes (v2 may have different signatures)\n#   4. go test .\u002F...\n\n# ⚠️ `go get -u` in CI is dangerous — it can break the build if a\n# dependency releases a breaking change. Pin versions in go.mod and\n# upgrade deliberately.\n",[29,890,891,896,915,919,924,932,940,953,957,962,973,981,989,993,998,1003,1008,1013,1018,1022,1027,1032],{"__ignoreMap":27},[32,892,893],{"class":34,"line":35},[32,894,895],{"class":38},"# Check for outdated dependencies:\n",[32,897,898,900,903,906,909,912],{"class":34,"line":42},[32,899,21],{"class":209},[32,901,902],{"class":349}," list",[32,904,905],{"class":576}," -m",[32,907,908],{"class":576}," -u",[32,910,911],{"class":349}," all",[32,913,914],{"class":38},"  # shows current and latest versions\n",[32,916,917],{"class":34,"line":48},[32,918,100],{"emptyLinePlaceholder":99},[32,920,921],{"class":34,"line":54},[32,922,923],{"class":38},"# Upgrade a single dependency:\n",[32,925,926,928,930],{"class":34,"line":60},[32,927,21],{"class":209},[32,929,350],{"class":349},[32,931,429],{"class":349},[32,933,934,936,938],{"class":34,"line":66},[32,935,21],{"class":209},[32,937,408],{"class":349},[32,939,411],{"class":349},[32,941,942,944,947,950],{"class":34,"line":72},[32,943,21],{"class":209},[32,945,946],{"class":349}," test",[32,948,949],{"class":349}," .\u002F...",[32,951,952],{"class":38},"  # ⚠️ always test after upgrading\n",[32,954,955],{"class":34,"line":78},[32,956,100],{"emptyLinePlaceholder":99},[32,958,959],{"class":34,"line":84},[32,960,961],{"class":38},"# Upgrade ALL dependencies (careful — may break things):\n",[32,963,964,966,968,970],{"class":34,"line":90},[32,965,21],{"class":209},[32,967,350],{"class":349},[32,969,908],{"class":576},[32,971,972],{"class":349}," .\u002F...\n",[32,974,975,977,979],{"class":34,"line":96},[32,976,21],{"class":209},[32,978,408],{"class":349},[32,980,411],{"class":349},[32,982,983,985,987],{"class":34,"line":103},[32,984,21],{"class":209},[32,986,946],{"class":349},[32,988,972],{"class":349},[32,990,991],{"class":34,"line":109},[32,992,100],{"emptyLinePlaceholder":99},[32,994,995],{"class":34,"line":115},[32,996,997],{"class":38},"# Major version upgrade (v1 → v2):\n",[32,999,1000],{"class":34,"line":121},[32,1001,1002],{"class":38},"#   1. Change the import path: \"github.com\u002Ffoo\u002Fbar\" → \"github.com\u002Ffoo\u002Fbar\u002Fv2\"\n",[32,1004,1005],{"class":34,"line":127},[32,1006,1007],{"class":38},"#   2. go mod tidy\n",[32,1009,1010],{"class":34,"line":133},[32,1011,1012],{"class":38},"#   3. Fix breaking API changes (v2 may have different signatures)\n",[32,1014,1015],{"class":34,"line":139},[32,1016,1017],{"class":38},"#   4. go test .\u002F...\n",[32,1019,1020],{"class":34,"line":145},[32,1021,100],{"emptyLinePlaceholder":99},[32,1023,1024],{"class":34,"line":151},[32,1025,1026],{"class":38},"# ⚠️ `go get -u` in CI is dangerous — it can break the build if a\n",[32,1028,1029],{"class":34,"line":157},[32,1030,1031],{"class":38},"# dependency releases a breaking change. Pin versions in go.mod and\n",[32,1033,1034],{"class":34,"line":163},[32,1035,1036],{"class":38},"# upgrade deliberately.\n",[14,1038,1040],{"id":1039},"tips-tricks","💡 Tips & Tricks",[1042,1043,1044,1059,1072,1082,1091,1097],"ul",{},[1045,1046,1047,1051,1052,1054,1055,1058],"li",{},[1048,1049,1050],"strong",{},"Idiom",": use ",[29,1053,173],{}," for packages that shouldn't be imported outside your module — the toolchain enforces the boundary. Reserve ",[29,1056,1057],{},"pkg\u002F"," for genuinely public, reusable packages.",[1045,1060,1061,1063,1064,1067,1068,1071],{},[1048,1062,1050],{},": ",[29,1065,1066],{},"go mod tidy"," before every commit — it adds missing deps and removes unused ones, keeping go.mod\u002Fgo.sum accurate. A CI check ",[29,1069,1070],{},"go mod tidy && git diff --exit-code"," prevents drift.",[1045,1073,1074,1051,1076,1078,1079,1081],{},[1048,1075,1050],{},[29,1077,767],{}," (Go 1.18+) for local multi-module development — it lets local edits to a library take effect in the app without ",[29,1080,465],{}," directives in go.mod (which break CI).",[1045,1083,1084,1086,1087,1090],{},[1048,1085,1050],{},": pin dependencies to specific versions in go.mod (committed) — ",[29,1088,1089],{},"go get @latest"," in CI can break the build. Upgrade deliberately, test after.",[1045,1092,1093,1096],{},[1048,1094,1095],{},"Safety",": commit both go.mod AND go.sum — they together define the build. go.sum provides supply-chain verification (hashes). Don't gitignore go.sum.",[1045,1098,1099,1101,1102,1105],{},[1048,1100,1050],{},": use GOPRIVATE for private repos so the Go tool uses git auth instead of the public proxy. Without it, ",[29,1103,1104],{},"go get"," fails with 404.",[14,1107,1109],{"id":1108},"️-edge-cases-gotchas","⚠️ Edge Cases & Gotchas",[1042,1111,1112,1128,1143,1152,1160,1171,1183,1196],{},[1045,1113,1114,1063,1120,1123,1124,1127],{},[1048,1115,1116,1117],{},"v2+ import paths require ",[29,1118,1119],{},"\u002Fv2",[29,1121,1122],{},"import \"github.com\u002Ffoo\u002Fbar\u002Fv2\""," — without the suffix, you get v1. The module's go.mod must also have ",[29,1125,1126],{},"module github.com\u002Ffoo\u002Fbar\u002Fv2",".",[1045,1129,1130,1135,1136,1138,1139,1142],{},[1048,1131,1132,1134],{},[29,1133,465],{}," in a library breaks consumers",": never commit ",[29,1137,465],{}," in a library's go.mod — consumers inherit it and break if they lack the local path. Use ",[29,1140,1141],{},"go.work"," instead.",[1045,1144,1145,1063,1148,1151],{},[1048,1146,1147],{},"Pseudo-versions are unstable",[29,1149,1150],{},"go get foo@main"," creates a pseudo-version tied to a commit hash. The commit changes → different build. Pin to tags for reproducibility.",[1045,1153,1154,1159],{},[1048,1155,1156,1158],{},[29,1157,1066],{}," may remove deps",": if you remove an import but don't run tidy, go.mod still lists the dep. Tidy cleans up — but also adds missing ones. Run it before committing.",[1045,1161,1162,1167,1168,1170],{},[1048,1163,1164,1166],{},[29,1165,681],{}," can have extra entries",": after an upgrade, go.sum may have hashes for multiple versions. ",[29,1169,1066],{}," cleans up unused entries.",[1045,1172,1173,1176,1177,1179,1180,1127],{},[1048,1174,1175],{},"Private modules need GOPRIVATE",": without it, ",[29,1178,1104],{}," tries the public proxy (returns 404 for private repos). Set ",[29,1181,1182],{},"go env -w GOPRIVATE=github.com\u002Fyourorg\u002F*",[1045,1184,1185,1191,1192,1195],{},[1048,1186,1187,1190],{},[29,1188,1189],{},"GOFLAGS=-mod=readonly"," prevents accidental go.mod changes",": in CI, use this to fail the build if go.mod needs modification. In dev, ",[29,1193,1194],{},"-mod=mod"," allows auto-updates.",[1045,1197,1198,1203],{},[1048,1199,1200,1202],{},[29,1201,173],{}," is enforced by the toolchain, not the filesystem",": the boundary is based on the module path, not the directory. A symlink outside the module can still import internal\u002F.",[14,1205,1207],{"id":1206},"quick-quiz","🧠 Quick Quiz",[19,1209,1210],{"language":278},[23,1211,1213],{"className":281,"code":1212,"language":278,"meta":27,"style":27},"# go.mod:\n#   module example.com\u002Fmyapp\n#   require github.com\u002Flib\u002Fpq v1.10.0\n#\n# go get github.com\u002Flib\u002Fpq@latest  # v1.10.9 is latest\n# What does go.mod say now?\n",[29,1214,1215,1220,1225,1230,1234,1239],{"__ignoreMap":27},[32,1216,1217],{"class":34,"line":35},[32,1218,1219],{"class":38},"# go.mod:\n",[32,1221,1222],{"class":34,"line":42},[32,1223,1224],{"class":38},"#   module example.com\u002Fmyapp\n",[32,1226,1227],{"class":34,"line":48},[32,1228,1229],{"class":38},"#   require github.com\u002Flib\u002Fpq v1.10.0\n",[32,1231,1232],{"class":34,"line":54},[32,1233,299],{"class":38},[32,1235,1236],{"class":34,"line":60},[32,1237,1238],{"class":38},"# go get github.com\u002Flib\u002Fpq@latest  # v1.10.9 is latest\n",[32,1240,1241],{"class":34,"line":66},[32,1242,1243],{"class":38},"# What does go.mod say now?\n",[1245,1246,1247,1251,1255,1263,1271,1278],"details",{},[1248,1249,1250],"summary",{},"Answer",[1252,1253,1254],"p",{},"go.mod now says:",[23,1256,1261],{"className":1257,"code":1259,"language":1260},[1258],"language-text","require github.com\u002Flib\u002Fpq v1.10.9\n","text",[29,1262,1259],{"__ignoreMap":27},[1252,1264,1265,1267,1268,1270],{},[29,1266,1089],{}," updates the require directive to the latest version. ",[29,1269,681],{}," is also updated with the v1.10.9 hash.",[1252,1272,1273,1274,1277],{},"But this is a ",[1048,1275,1276],{},"minor version upgrade"," (v1.10.0 → v1.10.9) — within the same major version (v1), so no import path change is needed.",[1252,1279,1280,1281,1284],{},"If the latest were v2.0.0, the import path would need to change to ",[29,1282,1283],{},"github.com\u002Flib\u002Fpq\u002Fv2"," — a breaking upgrade requiring code changes.",[14,1286,1288],{"id":1287},"whats-next","📚 What's Next",[1252,1290,1291,1292,1297,1298,1301],{},"→ ",[1293,1294,1296],"a",{"href":1295},"\u002Fgo\u002F22-io-and-files","22 — I\u002FO, Files & the io Package"," — Reader\u002FWriter composition, ",[29,1299,1300],{},"io.Copy",", buffered I\u002FO, and streaming patterns.",[1303,1304,1305],"style",{},"html pre.shiki code .sdCPZ, html code.shiki .sdCPZ{--shiki-default:#6A737D;--shiki-github-dark:#6A737D}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .github-dark .shiki span {color: var(--shiki-github-dark);background: var(--shiki-github-dark-bg);font-style: var(--shiki-github-dark-font-style);font-weight: var(--shiki-github-dark-font-weight);text-decoration: var(--shiki-github-dark-text-decoration);}html.github-dark .shiki span {color: var(--shiki-github-dark);background: var(--shiki-github-dark-bg);font-style: var(--shiki-github-dark-font-style);font-weight: var(--shiki-github-dark-font-weight);text-decoration: var(--shiki-github-dark-text-decoration);}html pre.shiki code .svdQ7, html code.shiki .svdQ7{--shiki-default:#D73A49;--shiki-github-dark:#F97583}html pre.shiki code .sIsaT, html code.shiki .sIsaT{--shiki-default:#6F42C1;--shiki-github-dark:#B392F0}html pre.shiki code .ssxIu, html code.shiki .ssxIu{--shiki-default:#24292E;--shiki-github-dark:#E1E4E8}html pre.shiki code .sJ6F3, html code.shiki .sJ6F3{--shiki-default:#032F62;--shiki-github-dark:#9ECBFF}html pre.shiki code .snvgF, html code.shiki .snvgF{--shiki-default:#005CC5;--shiki-github-dark:#79B8FF}",{"title":27,"searchDepth":42,"depth":42,"links":1307},[1308,1309,1311],{"id":16,"depth":42,"text":17},{"id":169,"depth":42,"text":1310},"The internal\u002F Enforcement",{"id":1287,"depth":42,"text":1288},"Module versioning semantics, internal\u002F enforcement, workspaces, replace directives, private modules, and the go.sum supply chain.","md",{},"\u002Fgo\u002F21-packages-and-modules",{"title":5,"description":1312},"go\u002F21-packages-and-modules","I_qwFf8xKSW2UygPrhbUNmRQwjTIcqds46nq0puU2Os",1789924648721]