Go Project Structure
Standard Go project layout following community conventions. Organize your Go projects for maintainability, testability, and clarity.
Use Case
Use this structure when you need to:
- Start a new Go project
- Organize a growing codebase
- Follow Go community standards
- Prepare for open source release
Standard Layout
1myproject/
2βββ cmd/ # Main applications
3β βββ myapp/
4β βββ main.go
5βββ internal/ # Private application code
6β βββ app/
7β βββ pkg/
8β βββ config/
9βββ pkg/ # Public library code
10β βββ api/
11β βββ utils/
12βββ api/ # API definitions (OpenAPI, Protocol Buffers)
13βββ web/ # Web assets
14βββ configs/ # Configuration files
15βββ scripts/ # Build and deployment scripts
16βββ test/ # Additional test data and helpers
17βββ docs/ # Documentation
18βββ examples/ # Example code
19βββ tools/ # Supporting tools
20βββ vendor/ # Vendored dependencies (optional)
21βββ go.mod # Module definition
22βββ go.sum # Dependency checksums
23βββ Makefile # Build automation
24βββ README.md
Explanation
cmd/- Main entry points, one subdirectory per executableinternal/- Private code, cannot be imported by other projectspkg/- Public library code, can be imported by othersapi/- API contracts (protobuf, OpenAPI specs)configs/- Configuration file templatestest/- Additional test files and test data
Examples
Example 1: Simple CLI Tool
1mycli/
2βββ cmd/
3β βββ mycli/
4β βββ main.go # Entry point
5βββ internal/
6β βββ command/ # Command implementations
7β β βββ init.go
8β β βββ run.go
9β β βββ status.go
10β βββ config/
11β βββ config.go # Configuration handling
12βββ go.mod
13βββ go.sum
14βββ Makefile
15βββ README.md
main.go:
1package main
2
3import (
4 "fmt"
5 "os"
6
7 "github.com/user/mycli/internal/command"
8)
9
10func main() {
11 if err := command.Execute(); err != nil {
12 fmt.Fprintf(os.Stderr, "Error: %v\n", err)
13 os.Exit(1)
14 }
15}
Example 2: Web Service
1myservice/
2βββ cmd/
3β βββ server/
4β βββ main.go
5βββ internal/
6β βββ handler/ # HTTP handlers
7β β βββ user.go
8β β βββ auth.go
9β βββ service/ # Business logic
10β β βββ user_service.go
11β βββ repository/ # Data access
12β β βββ user_repo.go
13β βββ model/ # Domain models
14β βββ user.go
15βββ pkg/
16β βββ client/ # Public API client
17β βββ client.go
18βββ api/
19β βββ openapi.yaml # API specification
20βββ configs/
21β βββ config.yaml
22βββ go.mod
23βββ README.md
main.go:
1package main
2
3import (
4 "log"
5 "net/http"
6
7 "github.com/user/myservice/internal/handler"
8 "github.com/user/myservice/internal/repository"
9 "github.com/user/myservice/internal/service"
10)
11
12func main() {
13 // Initialize dependencies
14 repo := repository.NewUserRepository()
15 svc := service.NewUserService(repo)
16 h := handler.NewHandler(svc)
17
18 // Setup routes
19 http.HandleFunc("/users", h.HandleUsers)
20
21 // Start server
22 log.Println("Server starting on :8080")
23 log.Fatal(http.ListenAndServe(":8080", nil))
24}
Example 3: Library with Examples
1mylib/
2βββ pkg/
3β βββ mylib/
4β βββ core.go
5β βββ core_test.go
6β βββ utils.go
7β βββ utils_test.go
8βββ examples/
9β βββ basic/
10β β βββ main.go
11β βββ advanced/
12β βββ main.go
13βββ docs/
14β βββ getting-started.md
15β βββ api.md
16βββ go.mod
17βββ go.sum
18βββ README.md
Example 4: Makefile
1.PHONY: build test clean run
2
3# Build binary
4build:
5 go build -o bin/myapp cmd/myapp/main.go
6
7# Run tests
8test:
9 go test -v ./...
10
11# Run tests with coverage
12test-coverage:
13 go test -v -coverprofile=coverage.out ./...
14 go tool cover -html=coverage.out
15
16# Run linter
17lint:
18 golangci-lint run
19
20# Format code
21fmt:
22 go fmt ./...
23
24# Tidy dependencies
25tidy:
26 go mod tidy
27
28# Run application
29run:
30 go run cmd/myapp/main.go
31
32# Clean build artifacts
33clean:
34 rm -rf bin/
35 rm -f coverage.out
36
37# Install dependencies
38deps:
39 go mod download
40
41# Build for multiple platforms
42build-all:
43 GOOS=linux GOARCH=amd64 go build -o bin/myapp-linux-amd64 cmd/myapp/main.go
44 GOOS=darwin GOARCH=amd64 go build -o bin/myapp-darwin-amd64 cmd/myapp/main.go
45 GOOS=windows GOARCH=amd64 go build -o bin/myapp-windows-amd64.exe cmd/myapp/main.go
Notes
- Use
internal/to prevent external imports of private code - Keep
pkg/for genuinely reusable code - One
main.goper executable incmd/ - Follow Go naming conventions (lowercase packages)
- Use
go modfor dependency management
Gotchas/Warnings
- β οΈ internal/: Cannot be imported from outside the project
- β οΈ pkg/: Only put stable, public APIs here
- β οΈ Flat structure: Small projects can stay flat - don't over-engineer
- β οΈ Vendor: Only vendor if you have specific requirements
comments powered by Disqus