Home

Organizing Go Projects: Best Practices and Conventions

24 views

In Go, having a well-organized project structure is crucial for maintainability, scalability, and collaboration. Go does not enforce a specific project structure, giving developers flexibility. However, certain conventions have emerged as best practices within the community. Below is an outline of a common Go project structure.

Basic Project Structure

A simple project might look like this:

myapp/
├── cmd/
│   └── myapp/
│       └── main.go
├── pkg/
│   └── mypackage/
│       └── mypackage.go
├── internal/
│   └── myinternal/
│       └── myinternal.go
├── api/
│   ├── v1/
│   │   └── api.proto
│   └── v2/
│       └── api.proto
├── configs/
│   └── config.yaml
├── scripts/
│   └── build.sh
├── web/
│   ├── static/
│   └── templates/
├── build/
│   ├── ci/
│   └── docker/
├── docs/
│   ├── README.md
│   └── api.md
├── vendor/
├── go.mod
└── go.sum

Directory Breakdown

  1. cmd/: This directory contains the entry points for your applications. Each subdirectory represents a different application.

    // cmd/myapp/main.go
    package main
    
    import (
        "myapp/pkg/mypackage"
        "fmt"
    )
    
    func main() {
        fmt.Println(mypackage.Hello())
    }
    
  2. pkg/: This directory is for libraries and packages that you want to share across multiple projects and applications.

    // pkg/mypackage/mypackage.go
    package mypackage
    
    func Hello() string {
        return "Hello, World!"
    }
    
  3. internal/: This directory contains packages that are meant to be used only within your project. This ensures encapsulation.

    // internal/myinternal/myinternal.go
    package myinternal
    
    func Secret() string {
        return "This is an internal secret"
    }
    
  4. api/: This directory is often used for defining API specifications, typically using protocol buffers (gRPC) or OpenAPI.

    // api/v1/api.proto
    syntax = "proto3";
    
    package v1;
    
    service Example {
        rpc SayHello (SayHelloRequest) returns (SayHelloResponse);
    }
    
    message SayHelloRequest {
        string name = 1;
    }
    
    message SayHelloResponse {
        string message = 1;
    }
    
  5. configs/: Configuration files like YAML, JSON, or TOML files.

    // configs/config.yaml
    debug: true
    port: 8080
    
  6. scripts/: Scripts for various tasks like building, running tests, or deployment.

    # scripts/build.sh
    #!/bin/sh
    go build -o myapp cmd/myapp/main.go
    
  7. web/: Assets for web servers, including static files (HTML, CSS, JavaScript) and templates.

    // web/templates/index.html
    <!DOCTYPE html>
    <html>
    <head>
        <title>My App</title>
    </head>
    <body>
        <h1>Welcome to My App</h1>
    </body>
    </html>
    
  8. build/: Infrastructure and CI/CD-related files.

    // build/ci/.gitlab-ci.yml
    stages:
     - build
    
    build-job:
      stage: build
      script:
        - go build cmd/myapp/main.go
    
  9. docs/: Project documentation. This could include README files, API documentation, etc.

    // docs/README.md
    # My App
    
    This is the README for My App.
    
  10. vendor/: Dependencies managed by Go Modules when vendoring is enabled. This is optional as Go Modules are generally handled automatically.

  11. go.mod and go.sum: These files are for dependency management with Go modules.

    // go.mod
    module myapp
    
    go 1.18
    

Practical Example

Here's a small practical example combining the above snippets:

// cmd/myapp/main.go
package main

import (
    "fmt"
    "myapp/pkg/mypackage"
    "myapp/internal/myinternal"
)

func main() {
    fmt.Println(mypackage.Hello())
    fmt.Println(myinternal.Secret())
}
// pkg/mypackage/mypackage.go
package mypackage

func Hello() string {
    return "Hello, World!"
}
// internal/myinternal/myinternal.go
package myinternal

func Secret() string {
    return "This is an internal secret"
}
# configs/config.yaml
debug: true
port: 8080
#!/bin/sh
# scripts/build.sh
go build -o myapp cmd/myapp/main.go

Conclusion

A well-structured Go project allows for easier navigation, maintenance, and collaboration. While Go doesn’t enforce a specific structure, following these conventions will help ensure that your projects are well-organized and scalable. The key is to remain consistent and use a structure that best fits the needs of your project.