Packages and Modules in Go: From Basics to Advanced

Go's package and module system is designed for dependency management and code organization. Let's explore it comprehensively.

Table of Contents

  1. Basic Package Concepts

  2. Creating Packages

  3. Importing Packages

  4. Visibility Rules

  5. Init Functions

  6. Go Modules

  7. Version Management

  8. Vendor Directory

  9. Advanced Patterns

  10. Best Practices

Basic Package Concepts

// File: greeter/greet.go
package greeter

func Hello() string {
    return "Hello, world!"
}

Creating Packages

  1. Create a directory for your package

  2. Add Go files with same package declaration

  3. Export functionality using capitalized names

Example structure:

mylib/
├── mathutil/
│   ├── math.go
│   └── stats.go
└── stringutil/
    └── strings.go

Importing Packages

Basic imports:

import (
    "fmt"
    "math/rand"
    "github.com/user/mylib/mathutil"
)

Aliased imports:

import (
    m "math"
    "github.com/user/mylib/mathutil"
)

Dot imports (avoid in production):

import . "fmt" // Now can use Println directly

Blank imports (for side effects):

import _ "image/png" // registers PNG decoder

Visibility Rules

package mylib

var privateVar int    // package-private
var PublicVar int     // exported

func privateFunc() {} // package-private
func PublicFunc() {}  // exported

Init Functions

package mylib

var config map[string]string

func init() {
    config = loadConfig()
}

func loadConfig() map[string]string {
    return map[string]string{"key": "value"}
}

Go Modules

Modules are Go's dependency management system:

  1. Initialize a module:
go mod init github.com/user/mymodule
  1. Resulting go.mod file:
module github.com/user/mymodule

go 1.21

require (
    github.com/some/dependency v1.2.3
)
  1. Key commands:
go mod tidy      # Add missing and remove unused modules
go get -u        # Update dependencies
go list -m all   # List all dependencies

Version Management

Example go get commands:

go get github.com/user/repo@v1.2.3
go get github.com/user/repo@latest
go get github.com/user/repo@master

Vendor Directory

Local copy of dependencies:

go mod vendor

This creates a vendor directory with all dependencies.

To use vendor:

go build -mod=vendor

Advanced Patterns

Internal Packages

Packages in internal/ are only importable by parent directory:

project/
├── internal/
│   └── utils/  # Only importable by project/ code
└── main.go

Submodules

Create nested modules:

project/
├── go.mod      # root module
├── submodule/
│   └── go.mod  # submodule

Plugin Architecture

// main.go
package main

import "plugin"

func loadPlugin(path string) {
    p, err := plugin.Open(path)
    if err != nil {
        panic(err)
    }
    sym, err := p.Lookup("Handler")
    if err != nil {
        panic(err)
    }
    handler := sym.(func(string))
    handler("Hello from plugin")
}

Build Constraints

Control compilation with file suffixes:

// File: app_linux.go
//go:build linux

package main

func init() {
    // Linux-specific initialization
}

Best Practices

  1. Keep packages focused - single responsibility

  2. Avoid circular dependencies

  3. Use semantic versioning properly

  4. Document exported elements with doc comments

  5. Minimize package-level variables

  6. Use internal/ for private packages

  7. Pin important dependencies to exact versions

  8. Regularly update dependencies (go get -u)

  9. Vendor dependencies for production deployments

  10. Use go.sum for reproducible builds

Complete Example

Module Structure

myapp/
├── go.mod
├── go.sum
├── main.go
└── internal/
    └── calculator/
        ├── add.go
        └── subtract.go

go.mod

module github.com/user/myapp

go 1.21

require (
    github.com/sirupsen/logrus v1.9.3
)

calculator/add.go

package calculator

// Add returns the sum of two integers
func Add(a, b int) int {
    return a + b
}

main.go

package main

import (
    "fmt"
    "github.com/sirupsen/logrus"
    "github.com/user/myapp/internal/calculator"
)

func main() {
    logrus.Info("Starting application")
    sum := calculator.Add(5, 3)
    fmt.Printf("5 + 3 = %d\\n", sum)
}
Quality Score: 10% (0 ratings)
Rate
Help Improve This Page
main.go
Terminal
Compiling & Running...
Ready. Press 'Run Code' to execute.