Packages & Modules
Packages are Go's way of organizing code. Modules are collections of packages with versioning. In this lesson, you'll learn how to create packages, use modules, and organize Go projects professionally.
What is a Package?
A package is a collection of Go source files in the same directory that are compiled together.
- Every Go file belongs to a package
- Package name is declared at the top:
package name - Package name should match directory name (convention)
mainpackage is specialβit's executable- Exported names start with capital letter
Creating a Package
// File: math/calculator.go
package math
// Add is exported (capital A)
func Add(a, b int) int {
return a + b
}
// subtract is not exported (lowercase s)
func subtract(a, b int) int {
return a - b
}
Using a Package
// File: main.go
package main
import (
"fmt"
"myproject/math" // Import custom package
)
func main() {
result := math.Add(5, 3)
fmt.Println(result) // 8
// math.subtract(5, 3) // Error: subtract is not exported
}
Go Modules
Modules are collections of packages with dependency management and versioning.
Creating a Module
# Initialize a new module
go mod init github.com/username/myproject
# This creates go.mod file
go.mod File
module github.com/username/myproject
go 1.21
require (
github.com/gorilla/mux v1.8.0
github.com/lib/pq v1.10.9
)
go mod init- Initialize modulego mod tidy- Add missing/remove unused dependenciesgo get package@version- Add/update dependencygo mod download- Download dependenciesgo mod vendor- Copy dependencies to vendor/
Project Structure
Standard Layout
myproject/
βββ go.mod
βββ go.sum
βββ main.go
βββ cmd/
β βββ server/
β βββ main.go
βββ internal/
β βββ auth/
β β βββ auth.go
β βββ database/
β βββ db.go
βββ pkg/
β βββ utils/
β βββ helpers.go
βββ vendor/
cmd/- Main applications (executables)internal/- Private packages (not importable by others)pkg/- Public packages (importable by others)vendor/- Vendored dependenciesapi/- API definitions (OpenAPI, Protocol Buffers)web/- Web assets (HTML, CSS, JS)
Import Statements
Import Styles
// Single import
import "fmt"
// Multiple imports
import (
"fmt"
"os"
"strings"
)
// Aliased import
import (
f "fmt"
str "strings"
)
// Blank import (for side effects)
import _ "github.com/lib/pq"
// Dot import (not recommended)
import . "fmt" // Now can use Println instead of fmt.Println
Import Paths
import (
// Standard library
"fmt"
"net/http"
// External packages
"github.com/gorilla/mux"
"github.com/lib/pq"
// Local packages
"myproject/internal/auth"
"myproject/pkg/utils"
)
goimports to format
automatically.
Exported vs Unexported
package user
// Exported type (capital U)
type User struct {
Name string // Exported field
email string // Unexported field
}
// Exported function
func NewUser(name, email string) *User {
return &User{
Name: name,
email: email,
}
}
// Exported method
func (u *User) GetEmail() string {
return u.email
}
// Unexported function
func validateEmail(email string) bool {
return strings.Contains(email, "@")
}
Package Initialization
package database
import "database/sql"
var db *sql.DB
// init runs automatically when package is imported
func init() {
var err error
db, err = sql.Open("postgres", "connection-string")
if err != nil {
panic(err)
}
}
func GetDB() *sql.DB {
return db
}
init() functions run automatically in
order:
- Imported packages' init functions
- Package-level variables
- Current package's init functions
Common Mistakes
1. Circular imports
// β Wrong - circular dependency
// package a imports package b
// package b imports package a
// Error: import cycle not allowed
// β
Correct - extract common code
// Create package c with shared code
// Both a and b import c
2. Package name doesn't match directory
// β Wrong
// Directory: utils/
// File: package helpers
// β
Correct
// Directory: utils/
// File: package utils
3. Not using go mod tidy
# β Wrong - manually editing go.mod
# Don't manually add dependencies
# β
Correct - use go commands
go get github.com/gorilla/mux
go mod tidy # Clean up
Exercise: Create a Math Package
Task: Create a reusable math package.
Requirements:
- Create a module called
mathlib - Create package
calculatorwith Add, Subtract, Multiply, Divide - Create package
geometrywith Circle and Rectangle types - Export appropriate functions and types
- Use from main.go
Show Solution
# Project structure
mathlib/
βββ go.mod
βββ main.go
βββ calculator/
β βββ calculator.go
βββ geometry/
βββ shapes.go
// go.mod
module mathlib
go 1.21
// calculator/calculator.go
package calculator
func Add(a, b float64) float64 {
return a + b
}
func Subtract(a, b float64) float64 {
return a - b
}
func Multiply(a, b float64) float64 {
return a * b
}
func Divide(a, b float64) (float64, error) {
if b == 0 {
return 0, fmt.Errorf("division by zero")
}
return a / b, nil
}
// geometry/shapes.go
package geometry
import "math"
type Circle struct {
Radius float64
}
func (c Circle) Area() float64 {
return math.Pi * c.Radius * c.Radius
}
func (c Circle) Perimeter() float64 {
return 2 * math.Pi * c.Radius
}
type Rectangle struct {
Width float64
Height float64
}
func (r Rectangle) Area() float64 {
return r.Width * r.Height
}
func (r Rectangle) Perimeter() float64 {
return 2 * (r.Width + r.Height)
}
// main.go
package main
import (
"fmt"
"mathlib/calculator"
"mathlib/geometry"
)
func main() {
// Calculator
sum := calculator.Add(10, 5)
fmt.Printf("10 + 5 = %.2f\n", sum)
diff := calculator.Subtract(10, 5)
fmt.Printf("10 - 5 = %.2f\n", diff)
product := calculator.Multiply(10, 5)
fmt.Printf("10 * 5 = %.2f\n", product)
quotient, err := calculator.Divide(10, 5)
if err != nil {
fmt.Println("Error:", err)
} else {
fmt.Printf("10 / 5 = %.2f\n", quotient)
}
// Geometry
circle := geometry.Circle{Radius: 5}
fmt.Printf("\nCircle (r=5):\n")
fmt.Printf(" Area: %.2f\n", circle.Area())
fmt.Printf(" Perimeter: %.2f\n", circle.Perimeter())
rect := geometry.Rectangle{Width: 4, Height: 6}
fmt.Printf("\nRectangle (4x6):\n")
fmt.Printf(" Area: %.2f\n", rect.Area())
fmt.Printf(" Perimeter: %.2f\n", rect.Perimeter())
}
Summary
- Packages organize code into reusable units
- Modules manage dependencies and versioning
- Exported names start with capital letter
- go.mod defines module and dependencies
- Standard layout: cmd/, internal/, pkg/
- init() runs automatically on import
- Avoid circular imports by extracting common code
What's Next?
Now that you understand packages and modules, you're ready to learn about File I/O. You'll discover how to read and write files, work with directories, and handle file operations in Go.
Enjoying these tutorials?