Go Project Structure
March 15, 2025As your Go projects grow, maintaining a well-organized structure becomes crucial for scalability and maintainability.
Common Go Project Layouts
There is no single “official” Go project structure, but here are some commonly used layouts:
Standard Go Project Layout (Recommended for Most Apps)
myproject/
│── cmd/ # Entry points (e.g., main.go)
│── internal/ # Private packages for internal use
│── pkg/ # Reusable packages (optional)
│── api/ # API definitions and handlers
│── configs/ # Configuration files
│── migrations/ # Database migration files
│── scripts/ # Utility scripts
│── test/ # Integration tests
│── go.mod # Module file
│── go.sum # Dependency checksums
Monorepo Style (For Microservices)
mycompany/
│── service1/
│ ├── cmd/
│ ├── internal/
│ ├── api/
│── service2/
│ ├── cmd/
│ ├── internal/
│ ├── api/
│── shared/
│ ├── pkg/
│ ├── utils/
│── go.work # Workspace file for managing multiple modules
Organizing Code in a Large Go Project
cmd/
- Entry Points
The cmd/
directory contains the entry point for your application. Each executable should have its own subdirectory.
Example: cmd/server/main.go
package main
import "myproject/internal/app"
func main() {
app.Start()
}
internal/
- Private Business Logic
Use the internal/
directory to store core business logic that should not be imported by other projects.
internal/
│── app/ # Application logic
│── database/ # Database interactions
│── services/ # Business services
│── handlers/ # HTTP handlers
pkg/
- Reusable Packages (Optional)
The pkg/
directory is for packages that can be reused across multiple projects.
Example: pkg/logger/logger.go
package logger
import "log"
func Info(msg string) {
log.Println("INFO:", msg)
}
api/
- API Definitions
Use api/
for defining API specifications, request/response models, and OpenAPI specifications.
Example: api/types.go
package api
type User struct {
ID int `json:"id"`
Name string `json:"name"`
Email string `json:"email"`
}
configs/
- Configuration Management
Store YAML, JSON, or environment-based configurations.
Example: configs/config.yaml
database:
host: "localhost"
port: 3306
user: "root"
password: "password"
test/
- Integration and Functional Tests
Keep integration tests separate from unit tests.
Example: test/user_test.go
package test
import (
"testing"
)
func TestUserCreation(t *testing.T) {
t.Log("User creation test")
}