Packages and Modules
Go modules, package organization, and dependency management
Introduction
In this lesson, you'll learn about packages and modules in Go. Coming from JavaScript, you already have a foundation for understanding this concept. We'll build on that knowledge while highlighting the key differences.
In JavaScript, you're familiar with go modules, package organization, and dependency management.
Go has its own approach to go modules, package organization, and dependency management, which we'll explore step by step.
The Go Way
Let's see how Go handles this concept. Here's a typical example:
// go.mod (like package.json)
// module github.com/user/my-app
// go 1.21
// require (
// github.com/gin-gonic/gin v1.9.1
// )
// Export: uppercase = exported, lowercase = unexported
package math // package declaration at top of every file
// Exported (public)
func Add(a, b int) int { return a + b }
const PI = 3.14159
// Unexported (private)
func helper() {}
// Import
package main
import (
"fmt" // stdlib
"math/rand" // stdlib subpackage
"github.com/user/my-app/math" // local package
"github.com/gin-gonic/gin" // external
mymath "github.com/user/my-app/math" // alias
)
func main() {
fmt.Println(math.Add(1, 2))
fmt.Println(math.PI)
}
// go commands
// go mod init github.com/user/my-app
// go get github.com/gin-gonic/gin
// go run main.go
// go build ./...
// go test ./...Comparing to JavaScript
Here's how you might have written similar code in JavaScript:
// package.json
// { "name": "my-app", "type": "module", ... }
// Import
import { add, subtract } from "./math.js";
import express from "express"; // npm package
import * as fs from "fs";
// Export
export function add(a, b) { return a + b; }
export const PI = 3.14159;
export default class App { ... }
// npm commands
// npm install express
// npm install --save-dev jest
// node index.jsYou may be used to different syntax or behavior.
Uppercase names are exported (public); lowercase are package-private
You may be used to different syntax or behavior.
go.mod is the module file (like package.json); go.sum is the lockfile
You may be used to different syntax or behavior.
Import path = module path + directory path (e.g. github.com/user/app/math)
You may be used to different syntax or behavior.
init() functions in packages run automatically before main()
You may be used to different syntax or behavior.
internal/ directory restricts package to parent module only
Step-by-Step Breakdown
1. Package Declaration
Every .go file starts with 'package name'. Files in the same directory must share the same package name.
// ES module: just export from any file// math/add.go
package math
func Add(a, b int) int { return a + b } // exported
func helper() {} // unexported2. Export by Capitalization
There are no export/import keywords in Go. Capitalized identifiers are automatically exported; lowercase are private to the package.
export function greet() {}
function helper() {} // privatefunc Greet() {} // exported — accessible from outside package
func helper() {} // unexported — package-private3. go.mod and Dependencies
go mod init creates go.mod with the module path. go get downloads dependencies and adds them to go.mod.
npm init
npm install expressgo mod init github.com/user/app
go get github.com/gin-gonic/gin
go mod tidy // remove unused deps4. init() Functions
Each package can have one or more init() functions that run automatically before main(). Good for one-time setup.
// No direct equivalent; use module-level side effects or IIFEpackage db
import "database/sql"
var pool *sql.DB
func init() {
var err error
pool, err = sql.Open("postgres", dsn)
if err != nil { panic(err) }
}Common Mistakes
When coming from JavaScript, developers often make these mistakes:
- Uppercase names are exported (public); lowercase are package-private
- go.mod is the module file (like package.json); go.sum is the lockfile
- Import path = module path + directory path (e.g. github.com/user/app/math)
Key Takeaways
- Uppercase = exported, lowercase = unexported — no export/import keywords
- go.mod defines module path and dependencies; go.sum is the lockfile
- Import path combines module path + relative directory: module/subdir/pkg
- init() runs automatically before main(); use sparingly for package-level setup