# Go Project Structure for CLI Applications: The Standard Layout Explained

> Master Go project structure for CLI apps. Learn the standard layout with cmd/, internal/, and pkg/ for scalable, testable tools. Build better command-line applications.

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

---

**The standard Go project layout places executable entry points in `cmd/`, private business logic in `internal/`, and public libraries in `pkg/` to create scalable, testable command-line tools.**

The `golang-standards/project-layout` repository defines the industry-standard directory hierarchy for Go applications. This structure provides a battle-tested blueprint for organizing CLI code that separates concerns, enforces encapsulation, and remains maintainable as your tool grows from a simple script to a complex multi-command application.

## The Core Directory Structure for Go CLI Projects

### cmd/ – Application Entry Points

The `cmd/` directory contains the bootstrap code for every executable your project produces. According to the repository's [`cmd/README.md`](https://github.com/golang-standards/project-layout/blob/main/cmd/README.md), each binary gets its own subdirectory (e.g., `cmd/myapp/`) containing a minimal [`main.go`](https://github.com/golang-standards/project-layout/blob/main/main.go) that wires together dependencies and invokes your internal packages. This directory should remain thin—only orchestration logic belongs here, not business rules.

### internal/ – Private Implementation Packages

The `internal/` directory houses packages that **cannot** be imported by external modules. As documented in [`internal/README.md`](https://github.com/golang-standards/project-layout/blob/main/internal/README.md), the Go compiler enforces this privacy boundary at the language level, making it the ideal location for application logic, domain models, and private helpers. This protection prevents accidental API leakage and allows you to refactor implementation details without breaking external consumers.

### pkg/ – Public Library Code

Use `pkg/` only when you explicitly intend to share code with other projects. The [`pkg/README.md`](https://github.com/golang-standards/project-layout/blob/main/pkg/README.md) explains that libraries placed here are importable by any module, making this directory suitable for reusable utilities, client SDKs, or public APIs that you version and distribute. If you do not need to support external imports, omit this directory entirely.

### Supporting Assets (configs/, scripts/, build/)

Non-Go files—configuration templates, CI/CD configs, build scripts, and deployment manifests—belong in dedicated directories like `configs/`, `scripts/`, and `build/`. This separation keeps your repository root tidy, distinguishes code from operational concerns, and makes the project structure immediately comprehensible to new contributors.

## Why This Layout Excels for CLI Development

According to the `golang-standards/project-layout` source documentation, this structure provides four critical advantages for command-line tools:

- **Separation of concerns**: The `cmd/` directory contains only entry-point orchestration, while heavy computation and business rules reside in importable, testable packages.
- **Compiler-enforced encapsulation**: The `internal/` package protection actively prevents other modules from importing implementation details, protecting your API surface.
- **Multi-binary support**: Adding new CLI tools requires only creating [`cmd/newtool/main.go`](https://github.com/golang-standards/project-layout/blob/main/cmd/newtool/main.go) without refactoring existing code or shared libraries.
- **Scalability**: The hierarchy accommodates growth from single-purpose scripts to complex applications with plugins, subcommands, and shared internal utilities.

## Complete Implementation Example

The following files demonstrate a minimal CLI application following the standard layout. The [`cmd/hello/main.go`](https://github.com/golang-standards/project-layout/blob/main/cmd/hello/main.go) file serves as the thin bootstrap, while [`internal/greeting/greeting.go`](https://github.com/golang-standards/project-layout/blob/main/internal/greeting/greeting.go) contains the actual logic protected from external import.

File: [`cmd/hello/main.go`](https://github.com/golang-standards/project-layout/blob/main/cmd/hello/main.go)

```go
package main

import (
	"fmt"
	"myproject/internal/greeting"
)

func main() {
	fmt.Println(greeting.Hello())
}

```

File: [`internal/greeting/greeting.go`](https://github.com/golang-standards/project-layout/blob/main/internal/greeting/greeting.go)

```go
package greeting

// Hello returns a friendly greeting.
// This package is private – only this module may import it.
func Hello() string {
	return "Hello, world!"
}

```

File: [`pkg/util/logger/logger.go`](https://github.com/golang-standards/project-layout/blob/main/pkg/util/logger/logger.go) (optional public helper)

```go
package logger

import "log"

// Info prints an informational message.
// Since this is under /pkg, other projects can import it.
func Info(msg string) {
	log.Printf("[INFO] %s", msg)
}

```

Run the application with:

```bash
go run ./cmd/hello

```

## Essential Documentation in the Repository

The `golang-standards/project-layout` repository provides authoritative guidance in these specific files:

- [`README.md`](https://github.com/golang-standards/project-layout/blob/main/README.md) – High-level overview of the entire layout and architectural rationale for each top-level directory.
- [`cmd/README.md`](https://github.com/golang-standards/project-layout/blob/main/cmd/README.md) – Conventions for organizing executable entry points and handling multiple binaries.
- [`internal/README.md`](https://github.com/golang-standards/project-layout/blob/main/internal/README.md) – Detailed explanation of the private `internal` pattern with real-world project examples.
- [`pkg/README.md`](https://github.com/golang-standards/project-layout/blob/main/pkg/README.md) – Guidelines for publishing public libraries, semantic versioning, and API compatibility guarantees.
- [`configs/README.md`](https://github.com/golang-standards/project-layout/blob/main/configs/README.md) – Standards for storing configuration templates and environment-specific files.
- [`scripts/README.md`](https://github.com/golang-standards/project-layout/blob/main/scripts/README.md) – Build automation, linting, testing, and release scripts tailored for CLI workflows.

## Summary

- Place **main packages** in `cmd/<app>/main.go` to define entry points for each executable binary.
- Store **private business logic** in `internal/` to leverage the Go compiler's import restrictions and prevent API leakage.
- Publish **public APIs** selectively in `pkg/` only when supporting external consumers and maintaining backward compatibility.
- Keep **configuration and operational scripts** in dedicated directories (`configs/`, `scripts/`) to maintain a clean repository root.
- This structure enables unit testing of core logic without invoking the command line, supporting true test-driven development.

## Frequently Asked Questions

### Should I use `internal/` or `pkg/` for my CLI's core logic?

Use `internal/` for all code that should remain implementation-specific to your module. The Go compiler actively prevents other modules from importing `internal/` packages, protecting your API surface from accidental dependencies. Reserve `pkg/` for libraries you explicitly intend to share with external projects, as these become part of your public API contract and require careful versioning.

### How do I structure a CLI with multiple commands or subcommands?

Create subdirectories under `cmd/` for each distinct binary (e.g., `cmd/server/`, `cmd/client/`). For a single binary with subcommands (using libraries like Cobra or Kong), keep the command definitions in `cmd/myapp/` but delegate all execution logic to packages in `internal/` or `pkg/`. This keeps the entry point thin and ensures business logic remains testable without executing through the CLI layer.

### Can I omit the `pkg/` directory entirely?

Yes. Many successful Go CLI projects use only `cmd/` and `internal/` directories. Include `pkg/` only when you need to expose specific packages for external import. According to the repository's guidance in [`pkg/README.md`](https://github.com/golang-standards/project-layout/blob/main/pkg/README.md), this directory is optional and should be used intentionally rather than by default.

### What belongs in the repository root versus `configs/`?

Place only metadata files (`go.mod`, `LICENSE`, [`README.md`](https://github.com/golang-standards/project-layout/blob/main/README.md)) and entry-point documentation in the root. Move all configuration templates, example YAML files, and environment-specific manifests into `configs/` to keep the root directory uncluttered. This distinction helps new contributors immediately identify the project's purpose without navigating through deployment artifacts.