Go Project Layout Patterns Used by Popular Go Projects: Standard Structure Explained
The Standard Go Project Layout organizes code into /cmd for executables, /internal for private packages, and /pkg for public libraries, a pattern adopted by Kubernetes, Prometheus, and Terraform to maintain scalable, compiler-enforced architectures.
The golang-standards/project-layout repository documents Go project layout patterns observed across the Go ecosystem to help developers structure applications as they grow. While not an official Go language standard, these conventions are implemented in major open-source repositories to separate concerns, enforce privacy boundaries through compiler rules, and create predictable codebases that scale from microservices to cloud-native platforms.
Core Directory Structure
The layout documented in the repository's README.md organizes projects into logical groups that separate executable entry points from reusable libraries and infrastructure configuration.
/cmd: Executable Entry Points
The /cmd directory contains the main package entry points for applications built by the project. According to cmd/README.md, this pattern keeps main functions minimal—typically just wiring dependency injection and calling into internal packages—while supporting multiple binaries from a single repository.
Major projects using this pattern include Velero, Moby, Prometheus, InfluxDB, Kubernetes, Dapr, and go-ethereum. Each subdirectory under /cmd represents a specific binary, such as /cmd/myapp/main.go.
/internal: Compiler-Enforced Privacy
The /internal directory stores private application code and library packages that external projects cannot import. As documented in internal/README.md, the Go compiler enforces this privacy: any package under an internal/ path can only be imported by code within the same module subtree.
Projects leveraging this enforcement include Terraform, InfluxDB, Perkeep, Jaeger, Moby, Satellity, and MinIO. This prevents accidental API leakage and clarifies which packages constitute the public surface area versus implementation details.
/pkg: Public Library APIs
The /pkg directory signals that contained code is safe for external consumption, though its use is optional and debated within the community. As noted in pkg/README.md, some teams place public libraries here while others use top-level directories directly.
Notable adopters include Containerd, Slim, Telepresence, Jaeger, Istio, Kaniko, and Gvisor. When present, /pkg provides a clear contract: packages here maintain backward compatibility, while code outside it (especially in /internal) does not.
Supporting Infrastructure Directories
Beyond code organization, the standard layout defines directories for non-Go assets and operational concerns:
/api– API protocol definitions (OpenAPI/Swagger, Protocol Buffers)/web– Static web assets and frontend templates/configs– Default configuration templates and schema files/deployments– Kubernetes manifests, Helm charts, and orchestration configs/scripts– Build and installation helper scripts (documented inscripts/README.md)/build– CI/CD configurations and packaging scripts (documented inbuild/README.md)/tools– Helper programs and development utilities/examples– Sample applications demonstrating API usage/vendor– Vendored third-party dependencies for reproducible builds
Real-World Implementation Example
A typical project following these Go project layout patterns structures code to maximize reusability while enforcing boundaries. The following examples demonstrate the relationship between /cmd, /internal, and /pkg.
Minimal Main Package
In /cmd/myapp/main.go, the entry point remains minimal, delegating to internal packages:
package main
import (
"log"
"github.com/yourorg/yourproj/internal/app"
)
func main() {
if err := app.Run(); err != nil {
log.Fatalf("application error: %v", err)
}
}
This pattern ensures the main function only handles process lifecycle concerns, while business logic resides in importable packages.
Private Application Logic
The /internal/app/app.go file contains implementation details that cannot be imported by external modules:
package app
import (
"fmt"
"github.com/yourorg/yourproj/internal/pkg/util"
)
func Run() error {
fmt.Println("starting app")
return util.DoWork()
}
Because this lives under /internal, the Go compiler prevents other repositories from importing github.com/yourorg/yourproj/internal/app.
Public Utility Libraries
Reusable code intended for external consumers resides in /pkg/util/util.go:
package util
import "fmt"
func DoWork() error {
fmt.Println("doing work in a public package")
return nil
}
External projects can safely import github.com/yourorg/yourproj/pkg/util, distinguishing public APIs from private implementation details.
Configuration Templates
Default configurations are stored in /configs/config.yaml for discovery at runtime:
port: 8080
log_level: info
This separation allows operators to mount configuration without modifying compiled binaries.
Module Configuration
The repository includes a minimal go.mod file demonstrating that these layout patterns work seamlessly with Go modules. The structure supports both library and application development without requiring special build tags or complex replace directives, making it compatible with standard go build and go install workflows.
Summary
- The
/cmddirectory houses executable entry points with minimalmainfunctions, adopted by Kubernetes and Prometheus to separate binary concerns from library code. - The
/internaldirectory provides compiler-enforced privacy for implementation details, preventing external import and used by Terraform and Jaeger. - The
/pkgdirectory optionally exposes stable public APIs for external consumption, implemented by Containerd and Istio. - Supporting directories like
/configs,/deployments, and/scriptsorganize operational assets separately from source code. - This layout is not an official Go standard but represents consensus patterns from high-scale open-source projects.
Frequently Asked Questions
Is the Standard Go Project Layout an official Go standard?
No, the Standard Go Project Layout documented in golang-standards/project-layout is not an official Go language specification. It is a community-curated collection of patterns observed in successful open-source projects. The Go team does not mandate any specific directory structure beyond what the go tool requires for modules.
What is the difference between /internal and /pkg in Go projects?
The /internal directory uses Go's compiler-level enforcement to prevent external packages from importing its contents, making it ideal for application-specific logic you want to keep private. The /pkg directory, by convention, signals that packages are intended for public use and should maintain backward compatibility, though its use is optional and some projects place public code at the root instead.
Which popular Go projects use the /cmd directory pattern?
Major infrastructure projects using the /cmd pattern include Kubernetes, Prometheus, InfluxDB, Velero, Moby (Docker), Dapr, and go-ethereum. These repositories place individual binary entry points in subdirectories like /cmd/kubelet or /cmd/server, keeping main packages isolated and small.
Should I use /pkg in my Go project?
Using /pkg depends on your project's scope. If you are building a library intended for external consumption, /pkg clearly signals stable public APIs, as seen in Containerd and Istio. However, for internal applications or when the entire repository is private, omitting /pkg and placing packages at the root may reduce unnecessary nesting. The pkg/README.md notes this convention is controversial and not universally accepted.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →