# How to Structure Go Projects for Open Source Libraries: The Complete Guide

> Structure your Go projects for open source libraries like a pro using the golang-standards/project-layout. Learn to organize APIs in pkg internals in internal and cmd for tools. Accelerate your development today.

- Repository: [golang-standards/project-layout](https://github.com/golang-standards/project-layout)
- Tags: best-practices
- Published: 2026-03-06

---

**Use the standard Go project layout to place public APIs in `/pkg`, private implementation in `/internal`, and auxiliary tools in `/cmd`, creating a directory structure that the Go toolchain recognizes and enforces automatically.**

When publishing a Go library, your directory layout signals to users and the compiler which code is intended for public consumption versus internal implementation details. The **golang-standards/project-layout** repository provides a battle-tested convention that major open-source projects use to organize code for maximum clarity, encapsulation, and maintainability.

## Core Directories for Library Organization

### /pkg – The Public API

Place reusable packages that other projects should import under `/pkg`. According to the [/pkg/README.md](https://github.com/golang-standards/project-layout/blob/master/pkg/README.md), this directory explicitly signals stable, versioned code ready for external use.

Import paths follow the pattern `github.com/youruser/yourlib/pkg/packagename`, making the API surface immediately discoverable.

### /internal – Encapsulated Implementation

The `/internal` directory contains packages that cannot be imported by external modules. As documented in [/internal/README.md](https://github.com/golang-standards/project-layout/blob/master/internal/README.md), the Go compiler actively enforces this boundary—attempting to import these packages from another module results in a build error.

Use this for helper code, adapters, and implementation details you want to refactor freely without breaking downstream consumers.

### /cmd – Command-Line Tools

Small binaries, demos, or utilities shipped with the library live in `/cmd`. Each subdirectory typically contains a separate `main` package. See [/cmd/README.md](https://github.com/golang-standards/project-layout/blob/master/cmd/README.md) for guidance on organizing multiple CLI tools.

### /examples and /test

Standalone programs demonstrating idiomatic usage belong in `/examples`, while integration tests and large test fixtures reside in `/test`. These directories, documented in [/examples/README.md](https://github.com/golang-standards/project-layout/blob/master/examples/README.md) and [/test/README.md](https://github.com/golang-standards/project-layout/blob/master/test/README.md), keep auxiliary code separate from the library core.

## Why This Layout Works for Open Source Libraries

- **Explicit Public API** – The `/pkg` directory creates an obvious import path structure that consumers can rely on for stable imports.
- **Compiler-Enforced Encapsulation** – The `/internal` directory provides hard boundaries that prevent accidental reliance on implementation details, allowing you to refactor private code without semantic version bumps.
- **Zero Configuration** – The layout works with standard Go tools (`go build`, `go test`, `go vet`) without additional build scripts or configuration files.
- **Community Familiarity** – Following the golang-standards/project-layout convention reduces onboarding friction for contributors who already recognize where to find code, tests, and documentation.

## Setting Up the Module Structure

Place a single `go.mod` file at the repository root to declare the module path:

```go
module github.com/youruser/yourlib

```

All packages under `/pkg` and `/internal` automatically belong to this module. The Go toolchain resolves imports correctly without extra configuration, and tagging the repository (e.g., `v1.2.3`) makes versions available through the module proxy immediately.

## Practical Implementation Examples

### Creating a Public Package in /pkg

```go
// /pkg/hello/hello.go
package hello

// Greet returns a friendly greeting.
func Greet(name string) string {
    if name == "" {
        name = "world"
    }
    return "Hello, " + name + "!"
}

```

Consumers import this using:

```go
import "github.com/youruser/yourlib/pkg/hello"

func main() {
    fmt.Println(hello.Greet("Alice"))
}

```

### Hiding Implementation Details in /internal

```go
// /internal/util/strings.go
package util

import "strings"

func toUpper(s string) string {
    return strings.ToUpper(s)
}

```

Attempting to import `github.com/youruser/yourlib/internal/util` from another module fails at compile time with: `use of internal package not allowed`.

### Building Example Programs

```go
// /examples/hello/main.go
package main

import (
    "fmt"
    "github.com/youruser/yourlib/pkg/hello"
)

func main() {
    fmt.Println(hello.Greet("")) // prints "Hello, world!"
}

```

Run the example directly:

```bash
go run ./examples/hello

```

### Packaging CLI Tools

```go
// /cmd/hello-cli/main.go
package main

import (
    "flag"
    "fmt"
    "github.com/youruser/yourlib/pkg/hello"
)

func main() {
    name := flag.String("name", "", "Name to greet")
    flag.Parse()
    fmt.Println(hello.Greet(*name))
}

```

Build and install locally:

```bash
go build -o bin/hello-cli ./cmd/hello-cli
./bin/hello-cli -name=Bob

```

## Essential Documentation Files

The golang-standards/project-layout repository provides self-documenting README files that explain each directory's purpose:

- [/README.md](https://github.com/golang-standards/project-layout/blob/master/README.md) – Overview of the layout and rationale
- [/pkg/README.md](https://github.com/golang-standards/project-layout/blob/master/pkg/README.md) – Guidelines for public package organization
- [/internal/README.md](https://github.com/golang-standards/project-layout/blob/master/internal/README.md) – Rules for encapsulated packages
- [/cmd/README.md](https://github.com/golang-standards/project-layout/blob/master/cmd/README.md) – Tool and binary organization
- [/examples/README.md](https://github.com/golang-standards/project-layout/blob/master/examples/README.md) – Example program structure
- [/test/README.md](https://github.com/golang-standards/project-layout/blob/master/test/README.md) – Integration testing and fixtures

## Summary

- Place public, stable APIs in `/pkg` to signal importable code and create clear import paths
- Use `/internal` for implementation details the compiler protects from external modules
- Add `/cmd` for binaries, `/examples` for documentation via working code, and `/test` for integration suites
- Maintain one `go.mod` at the repository root to define the module boundary
- Reference the golang-standards/project-layout documentation to ensure your structure matches community expectations

## Frequently Asked Questions

### What is the difference between /pkg and /internal in Go projects?

The `/pkg` directory contains packages intended for external import and long-term stability, while `/internal` houses private implementation details. The Go compiler enforces that packages under `/internal` cannot be imported by code outside the module that contains them, providing automatic API boundaries that prevent accidental dependency on unstable internals.

### Should I put all my library code in /pkg or just the public API?

Only place packages you explicitly intend for public consumption in `/pkg`. Implementation helpers, adapters, and code you may refactor frequently should remain in `/internal` or at the root level if module-private but not necessarily secret. This distinction helps you manage semantic versioning by clarifying what constitutes a breaking change.

### Where should I place command-line tools in a Go library project?

Place small command-line programs, demos, and utilities in `/cmd`. Each subdirectory under `/cmd` should contain a separate `main` package (e.g., [`/cmd/myapp/main.go`](https://github.com/golang-standards/project-layout/blob/main//cmd/myapp/main.go)). This keeps the library core separate from executable code while providing a standard location for tooling shipped alongside the library, as recommended in the project's [/cmd/README.md](https://github.com/golang-standards/project-layout/blob/master/cmd/README.md).

### Does the golang-standards/project-layout work with Go modules?

Yes, the layout is fully compatible with Go modules. Place a single `go.mod` file at the repository root declaring the module path (e.g., `module github.com/user/repo`). The module system applies to all subdirectories including `/pkg` and `/internal`, and the Go toolchain resolves imports correctly without additional configuration or custom build scripts.