Skip to Content
Go Realm v1 is released 🎉

Golang Packages: Comprehensive Notes

Package Fundamentals

What is a Package in Go?

A package is a collection of related Go source files that are compiled together. Packages provide:

  • Code organization
  • Namespace management
  • Code reusability
  • Access control

Basic Package Structure

myproject/ ├── go.mod # Module definition ├── main.go # Main package └── utils/ ├── math.go # Utility package └── strings.go # Utility package

Creating and Using Packages

Package Declaration

// Every file must start with package declaration package utils // Exported function (capitalized) func Add(a, b int) int { return a + b } // Unexported function (lowercase) func internalHelper() { // ... }

Importing Packages

import ( "fmt" // Standard library "math/rand" // Subpackage "github.com/user/repo/pkg" // Third-party "./utils" // Local package (relative path) myalias "some/long/package/path" // Aliased import )

Package Initialization

init() Function

package db var connection string func init() { // Runs when package is first imported connection = os.Getenv("DB_CONN") fmt.Println("Database package initialized") }

⚠️ Avoid complex logic in init() functions as initialization order can be tricky to debug.

Initialization Order

  1. Package-level variable initialization
  2. init() functions in order of declaration
  3. Main package execution

Visibility Rules

Naming ConventionVisibility
UpperCaseExported
lowerCaseUnexported
package models type User struct { // Exported Name string // Exported age int // Unexported } func NewUser() User { // Exported return User{} } func validate(u User) bool { // Unexported return u.age > 0 }

Advanced Package Concepts

Internal Packages

// Inside project/internal/auth/authenticator.go package auth // Only accessible within the parent module func Authenticate() bool { // ... }

Vendor Directory

# Create vendor directory with dependencies go mod vendor # Build using vendor directory go build -mod=vendor

Package Documentation

// Calculator provides basic arithmetic operations package calculator // Add returns the sum of two integers // // Example: // // sum := Add(3, 4) // returns 7 func Add(a, b int) int { return a + b }

Common Patterns

Factory Pattern

package shapes type Shape interface { Area() float64 } func NewShape(shapeType string) Shape { switch shapeType { case "circle": return &Circle{} case "rectangle": return &Rectangle{} default: return nil } }

Configuration Packages

package config type Config struct { Port int Database string } var AppConfig Config func init() { AppConfig = loadConfig() } func loadConfig() Config { // Load from file/env }

Package Management

go.mod File

module github.com/user/myapp go 1.21 require ( github.com/lib/pq v1.10.9 golang.org/x/text v0.14.0 ) replace github.com/old/package => github.com/new/package v1.2.3

Common Commands ⭐

# Initialize new module go mod init github.com/user/repo # Add dependencies go get github.com/pkg/errors@latest # Tidy dependencies go mod tidy # Verify dependencies go mod verify

Best Practices

  1. Keep packages focused: Single responsibility principle
  2. Avoid circular dependencies: Refactor into common package if needed
  3. Minimal exported API: Only expose what’s necessary
  4. Clear documentation: Every exported element should be documented
  5. Consistent naming: Follow standard library conventions

💡 The Go standard library is an excellent resource for learning good package design patterns.

FAQ

Q1: What’s the difference between a package and a module?

A: A package is a collection of Go source files in the same directory. A module is a collection of related Go packages with versioned dependencies defined in a go.mod file.

Q2: How does Go handle package versioning?

A: Go uses semantic versioning (v1.2.3) and records specific versions in go.mod. It supports minimal version selection (MVS) for dependency resolution.

Q3: What is the purpose of the internal directory?

A: Packages inside internal are only importable by other packages within the same parent module, providing a way to create private shared code.

Q4: How would you structure a large Go project?

A: Typical structure:

project/ ├── cmd/ # Main applications │ └── app1/ │ └── main.go ├── internal/ # Private code ├── pkg/ # Library code ├── api/ # API contracts ├── configs/ # Configuration ├── scripts/ # Build scripts └── go.mod

Q5: What’s the difference between go install and go get?

A:

  • go get downloads and installs packages, updating go.mod
  • go install compiles and installs binaries to $GOPATH/bin

Q6: How do you handle package initialization with dependencies?

A: Use init() functions sparingly. For complex initialization, consider explicit initialization functions that are called by the main package.

Q7: What are blank imports (_) used for?

A: Blank imports are used when you need a package’s initialization side effects (like database drivers registering themselves) but don’t need to use the package directly.

Q8: How would you create a package that provides multiple implementations?

A: Use build tags or separate packages with a common interface:

// +build mysql package database import _ "github.com/go-sql-driver/mysql"

Q9: What’s the purpose of the vendor directory?

A: The vendor directory contains all dependency packages, allowing builds to work without downloading dependencies and ensuring reproducible builds.

Q10: How do you document a Go package?

A:

  1. Package comment above package declaration
  2. Comments for each exported element
  3. Can generate docs with go doc or view at pkg.go.dev