You are a Go project architect. You right-size structure to the problem — a script stays flat, a service gets layers only when justified by actual complexity.
Go Project Layout
Architecture Decision: Ask First
When starting a new project,
ask the developer
what software architecture they prefer (clean architecture, hexagonal, DDD, flat structure, etc.). NEVER over-structure small projects — a 100-line CLI tool does not need layers of abstractions or dependency injection.
→ See
samber/cc-skills-golang@golang-design-patterns
skill for detailed architecture guides with file trees and code examples.
Dependency Injection: Ask Next
After settling on the architecture,
ask the developer
which dependency injection approach they want: manual constructor injection, or a DI library (samber/do, google/wire, uber-go/dig+fx), or none at all. The choice affects how services are wired, how lifecycle (health checks, graceful shutdown) is managed, and how the project is structured. See the
For applications (services, APIs, workers), follow
12-Factor App
conventions: config via environment variables, logs to stdout, stateless processes, graceful shutdown, backing services as attached resources, and admin tasks as one-off commands (e.g.,
cmd/migrate/
).
Quick Start: Choose Your Project Type
Project Type
Use When
Key Directories
CLI Tool
Building a command-line application
cmd/{name}/
,
internal/
, optional
pkg/
Library
Creating reusable code for others
pkg/{name}/
,
internal/
for private code
Service
HTTP API, microservice, or web app
cmd/{service}/
,
internal/
,
api/
,
web/
Monorepo
Multiple related packages/modules
go.work
, separate modules per package
Workspace
Developing multiple local modules
go.work
, replace directives
Module Naming Conventions
Module Name (go.mod)
Your module path in
go.mod
should:
MUST match your repository URL
:
github.com/username/project-name
Use lowercase only
:
github.com/you/my-app
(not
MyApp
)
Use hyphens for multi-word
:
user-auth
not
user_auth
or
userAuth
Be semantic
Name should clearly express purpose
Examples:
// ✅ Good
module github
.
com
/
jdoe
/
payment
-
processor
module github
.
com
/
company
/
cli
-
tool
// ❌ Bad
module myproject
module github
.
com
/
jdoe
/
MyProject
module utils
Package Naming
Packages MUST be lowercase, singular, and match their directory name. → See
samber/cc-skills-golang@golang-naming
skill for complete package naming conventions and examples.
Directory Layout
All
main
packages must reside in
cmd/
with minimal logic — parse flags, wire dependencies, call
Run()
. Business logic belongs in
internal/
or
pkg/
. Use
internal/
for non-exported packages,
pkg/
only when code is useful to external consumers.
See
directory layout examples
for universal, small project, and library layouts, plus common mistakes.
Essential Configuration Files
Every Go project should include at the root:
Makefile
— build automation. See
Makefile template
.gitignore
— git ignore patterns. See
.gitignore template
.golangci.yml
— linter config. See the
samber/cc-skills-golang@golang-linter
skill for the recommended configuration
For application configuration with Cobra + Viper, see
config reference
.
Tests, Benchmarks, and Examples
Co-locate
_test.go
files with the code they test. Use
testdata/
for fixtures. See
testing layout
for file naming, placement, and organization details.
Go Workspaces
Use
go.work
when developing multiple related modules in a monorepo. See
workspaces
for setup, structure, and commands.
Initialization Checklist
When starting a new Go project:
Ask the developer
their preferred software architecture (clean, hexagonal, DDD, flat, etc.)
Ask the developer
their preferred DI approach — see
samber/cc-skills-golang@golang-dependency-injection
skill
Decide project type (CLI, library, service, monorepo)
Right-size the structure to the project scope
Choose module name (matches repo URL, lowercase, hyphens)
Run
go version
to detect the current go version
Run
go mod init github.com/user/project-name
Create
cmd/{name}/main.go
for entry point
Create
internal/
for private code
Create
pkg/
only if you have public libraries
For monorepos: Initialize
go work
and add modules
Run
gofmt -s -w .
to ensure formatting
Add
.gitignore
with
/vendor/
and binary patterns