1. go
  2. /best practices
  3. /project-structure

Project Structure Best Practices in Go

A well-organized project structure is crucial for maintainability, scalability, and collaboration. This guide covers best practices for structuring Go projects.

Core Principles

1. Package Organization

Go projects should follow these package organization principles:

  1. Package Names:

    • Use simple, clear, lowercase names
    • Avoid underscores or mixedCaps
    • Name should reflect purpose
    • Keep names short but meaningful
  2. Package Structure:

    • Group related functionality
    • Avoid circular dependencies
    • Maintain clear boundaries
    • Design for reusability
  3. Import Organization:

    • Standard library imports first
    • Third-party imports second
    • Local package imports last
    • Use blank lines between groups

Standard Project Layout

A typical Go project should follow this structure:

project-root/
├── cmd/                    # Main applications
│   └── myapp/             # Application-specific code
│       └── main.go        # Application entry point
├── internal/              # Private code
│   ├── auth/             # Authentication package
│   ├── database/         # Database package
│   └── server/           # Server package
├── pkg/                   # Public libraries
│   ├── models/           # Data models
│   └── utils/            # Utility functions
├── api/                   # API definitions
│   └── openapi/          # OpenAPI/Swagger specs
├── web/                   # Web assets
│   ├── static/           # Static files
│   └── templates/        # HTML templates
├── configs/              # Configuration files
├── scripts/              # Build and automation scripts
├── test/                 # Additional test files
├── docs/                 # Documentation
├── examples/             # Example code
├── third_party/          # Third-party tools
├── vendor/               # Vendored dependencies
├── .gitignore           # Git ignore file
├── go.mod               # Go modules file
├── go.sum               # Go modules checksum
├── Makefile             # Build automation
└── README.md            # Project documentation

Directory Purposes

  1. cmd/

    • Contains main applications
    • Each subdirectory is a separate executable
    • Keep main.go simple and focused
    • Move logic to internal/ or pkg/
  2. internal/

    • Private application code
    • Not importable by other projects
    • Protected by Go compiler
    • Perfect for business logic
  3. pkg/

    • Public libraries
    • Importable by other projects
    • Well-documented APIs
    • Stable interfaces
  4. api/

    • API definitions
    • Protocol documentation
    • OpenAPI/Swagger specs
    • gRPC protocol definitions

Package Design Principles

1. Package Cohesion

Packages should have a single, well-defined purpose:

// Good: focused package
package validation

type Validator interface {
    Validate() error
}

// Bad: mixed concerns
package utils // Avoid catch-all packages

2. Package Coupling

Minimize dependencies between packages:

// Good: clear dependencies
package orders

import (
    "myapp/internal/customers"
    "myapp/internal/products"
)

// Bad: circular dependencies
package a
import "myapp/internal/b"

package b
import "myapp/internal/a"

3. Package Interfaces

Define interfaces at package boundaries:

// Good: interface in consuming package
package service

type Repository interface {
    Find(id string) (*Entity, error)
    Save(entity *Entity) error
}

// Bad: concrete dependencies
type Service struct {
    repo *postgres.Repository // Avoid concrete types
}

Application Structure Patterns

1. Layer Pattern

Organize code by technical responsibility:

internal/
├── handlers/    # HTTP handlers
├── services/    # Business logic
├── repositories/ # Data access
└── models/      # Data structures

2. Domain-Driven Design

Organize code by business domain:

internal/
├── ordering/    # Order management
├── catalog/     # Product catalog
├── shipping/    # Shipping logic
└── billing/     # Payment processing

3. Clean Architecture

Organize code by dependency direction:

internal/
├── domain/     # Business entities
├── usecase/    # Application logic
├── interface/  # External interfaces
└── infrastructure/ # Implementation details

Best Practices

1. Dependency Management

  • Use Go modules for dependency management
  • Vendor dependencies when needed
  • Keep dependencies up to date
  • Regularly audit dependencies

2. Configuration Management

  • Use environment variables for configuration
  • Keep configs in a dedicated package
  • Support multiple environments
  • Use strong typing for config

3. Testing Organization

  • Keep tests alongside code
  • Use table-driven tests
  • Organize integration tests separately
  • Maintain test helpers

Common Anti-patterns

1. Avoid Deep Package Hierarchies

// Bad
import "myapp/pkg/services/handlers/api/v1/users"

// Good
import "myapp/pkg/users"

2. Avoid Utility Packages

// Bad
package utils

// Good
package stringutil
package timeutil

3. Avoid Package Name Stuttering

// Bad
package stringutil
func stringutil.StringConvert()

// Good
package stringutil
func Convert()

Project Examples

1. Basic Service

myservice/
├── cmd/
│   └── server/
│       └── main.go
├── internal/
│   ├── api/
│   ├── service/
│   └── storage/
├── pkg/
│   └── models/
└── configs/

2. Microservice

microservice/
├── cmd/
│   └── api/
├── internal/
│   ├── domain/
│   ├── ports/
│   └── adapters/
├── pkg/
│   └── shared/
└── api/
    └── proto/

Next Steps