Golang Project Layout
Samuel BertheCommunityCreated by samberDistributed by Samuel Berthe
- Skill
- Guidelines
- Software development
- MIT
- No issues found
AutoGineer summary
Written by AutoGineer from the skill’s own files, not by the author
This skill provides architectural guidance for structuring Go projects based on established community conventions. It covers the use of cmd, internal, and pkg directories, module naming requirements, and the setup of Go workspaces. The skill emphasizes right-sizing project structures to match complexity, ensuring that main packages remain thin while business logic is appropriately encapsulated. It also provides templates for essential configuration files like Makefiles and .gitignore, and outlines a systematic approach to initializing new Go projects.
What it does
- Defines standard directory conventions for CLI tools, services, and libraries.
- Provides guidelines for module naming and package organization.
- Offers templates for essential project files including Makefiles and .gitignore.
- Explains the use of go.work for managing monorepos and local module development.
- Outlines a step-by-step initialization checklist for new Go projects.
- Promotes the separation of entry points in cmd/ from business logic in internal/.
When to use it
- When starting a new Go project and needing a standard file structure.
- When organizing an existing codebase to improve maintainability.
- When setting up a monorepo or managing multiple packages within a single workspace.
- When creating CLI tools that require multiple main packages.
- When discussing package restructuring or module splits.
Advantages
- Ensures project structure aligns with common Go community standards.
- Prevents common pitfalls by separating public and private code.
- Simplifies build automation and dependency management.
- Provides a clear path for scaling from simple tools to complex services.
Usage examples
- “How should I structure a new Go service project?”
- The agent will guide you through selecting an architecture, choosing a DI approach, and setting up the cmd/ and internal/ directories according to the 12-Factor App conventions.
- “I need to add a second binary to my existing Go project, how do I do that?”
- The agent will explain the cmd/ directory convention, showing you how to add a new subdirectory under cmd/ for the new main package while keeping existing logic separate.
- “How do I set up a monorepo for my Go packages?”
- The agent will provide instructions on using go.work to manage multiple local modules and explain how to structure the repository for shared and independent packages.
Install
Download the skill as a ZIP:
https://autogineer.com/agent-skills/samber/golang-project-layout/downloadUnzip it into the cross-client skills folder of your project:
mkdir -p .agents/skills && unzip golang-project-layout.zip -d .agents/skills
Documentation by samber
Persona: 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.
Questions: Ask the user through the environment's question tool — never as plain-text prose. Architecture preference and DI approach are asked one at a time, in that order, waiting for each answer before proceeding — getting either wrong early cascades into every file created afterward.
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.). Avoid over-structuring 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 samber/cc-skills-golang@golang-dependency-injection skill for a full comparison and decision table.
12-Factor App
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-nameUse lowercase only:
github.com/you/my-app(notMyApp)Use hyphens for multi-word:
user-authnotuser_authoruserAuthBe 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 utilsPackage 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-lintskill 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:
[ ] Confirm preferred software architecture (clean, hexagonal, DDD, flat, etc.)
[ ] Confirm preferred DI approach — see
samber/cc-skills-golang@golang-dependency-injectionskill[ ] 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 versionto detect the current go version[ ] Run
go mod init github.com/user/project-name[ ] Create
cmd/{name}/main.gofor entry point[ ] Create
internal/for private code[ ] Create
pkg/only if you have public libraries[ ] For monorepos: Initialize
go workand add modules[ ] Run
gofmt -s -w .to ensure formatting[ ] Add
.gitignorewith/vendor/and binary patterns[ ] Write the always-load directive for
samber/cc-skills-golang@golang-how-tointo the project's agent-config file (CLAUDE.md, AGENTS.md, or equivalent) — no user confirmation needed, see that skill's Configure mode
Related Skills
→ See
samber/cc-skills-golang@golang-cliskill for CLI tool structure and Cobra/Viper patterns.→ See
samber/cc-skills-golang@golang-dependency-injectionskill for DI approach comparison and wiring.→ See
samber/cc-skills-golang@golang-lintskill for golangci-lint configuration.→ See
samber/cc-skills-golang@golang-continuous-integrationskill for CI/CD pipeline setup.→ See
samber/cc-skills-golang@golang-design-patternsskill for architectural patterns.→ See
samber/cc-skills-golang@golang-refactoringskill for safely moving or splitting existing code into the layout above via type-alias gradual code repair and staged PRs, without a big-bang break.→ See
samber/cc-skills-golang@golang-how-toskill's Configure mode for the always-load directive and optional## Required Go skillsblock written to the project's agent-config file (CLAUDE.md, AGENTS.md, or equivalent).
Files
- ATTRIBUTION.mdAdded by AutoGineer920 B
- LICENSELicence file added by AutoGineer1.0 KiB
- SKILL.md7.2 KiB
- assets/.gitignore421 B
- assets/Makefile2.5 KiB
- evals/evals.json11.7 KiB
- references/config.md1.4 KiB
- references/directory-layouts.md5.1 KiB
- references/testing-layout.md5.5 KiB
- references/workspaces.md2.7 KiB
references/testing-layout.md
Tests, Benchmarks, and Examples
Table of Contents
File Naming Conventions
Where to Place Tests
Test Package Options
Benchmarks
Examples
Test Utilities
Test Fixtures
Running Tests
Test File Summary
File Naming Conventions
Go uses suffix-based naming for test-related files:
| Suffix | Purpose | Build Tag |
|---|---|---|
_test.go | Tests | Not included in normal builds |
_bench_test.go | Benchmarks | Not included in normal builds |
_example_test.go | Examples that verify output | Not included in normal builds |
| No suffix | Regular code | Included in all builds |
Where to Place Tests
Co-locate tests with the code they test:
internal/
├── handler/
│ ├── handler.go # Production code
│ ├── handler_test.go # Tests for handler
│ └── handler_bench_test.go # Benchmarks (optional)
├── service/
│ ├── service.go
│ └── service_test.go
└── model/
├── user.go
└── user_test.go
pkg/
└── logger/
├── logger.go
└── logger_test.goKey principles:
Tests live in the same package as the code (e.g.,
package handler)Test files are in the same directory as the code they test
Use
_test.gosuffix for all test files
Test Package Options
When writing tests, you have two options for the package declaration:
Option 1: Same package (white-box testing)
package handler // Same package, can access unexported
import "testing"
func TestHandler(t *testing.T) {
// Can access unexported functions and types
internalFunction()
}Option 2: Package with _test suffix (black-box testing)
package handler_test // Different package, only exported API
import "testing"
func TestHandler(t *testing.T) {
// Can only access exported functions and types
handler.PublicMethod()
}When to use each:
Use same package for unit tests that need to test internals
Use
_testsuffix for integration/behavioral tests
Benchmarks
Benchmarks use the _bench_test.go suffix and contain functions with the Benchmark prefix.
Examples
Examples serve two purposes: documentation and verification.
In libraries - use *_example_test.go files:
pkg/
└── logger/
├── logger.go
├── logger_test.go
└── logger_example_test.go # ExamplesExample function format:
package logger
import "fmt"
func ExampleLogger_Info() {
log := New()
log.Info("processing started")
log.Info("processing complete")
// Output:
// INFO: processing started
// INFO: processing complete
}Key points:
Example functions must start with
ExampleThe
// Output:comment verifies the outputExamples are runnable tests:
go testwill fail if output doesn't matchgodocdisplays examples as documentationFile name format:
{package}_example_test.go(e.g.,logger_example_test.go)
For executable examples (standalone demo programs):
examples/
└── basic-usage/
└── main.go # Executable exampleTest Utilities
When you have shared test helpers, use a dedicated package:
test/
└── testutils/
├── mock.go
└── fixtures.goOr use the internal/testutil pattern:
internal/
└── testutil/
├── mock.go
└── fixtures.goTest Fixtures
Fixtures are test data files used across multiple tests. Use one of these patterns:
Option 1: Local testdata directory (package-specific fixtures)
internal/
└── handler/
├── handler.go
├── handler_test.go
└── testdata/
├── users.json
├── request_valid.json
└── request_invalid.jsonOption 2: Global test directory (shared across packages)
test/
└── fixtures/
├── users.json
├── products.json
└── responses/
├── success.json
└── error.jsonOption 3: Embedded fixtures (Go 1.16+, use //go:embed)
internal/
└── handler/
├── handler.go
├── handler_test.go
└── testdata/
└── users.jsonImportant notes:
Go ignores the
testdatadirectory when building regular packagesUse
testdata/for package-specific test dataUse
test/fixtures/for cross-package shared fixturesDon't put
.gofiles intestdata/- they will be ignored
Running Tests
go test ./... # Run all tests
go test ./internal/handler # Test specific package
go test -v ./... # Verbose output
go test -race ./... # Race detection
go test -cover ./... # Coverage report
go test -short ./... # Skip long-running testsTest File Summary
| File Type | Suffix | Package | Purpose |
|---|---|---|---|
| Test | *_test.go | package X or package X_test | Unit/integration tests |
| Benchmark | *_bench_test.go | Same as code | Performance tests |
| Example (godoc) | *_example_test.go | Same as code | Documentation + verification |
| Executable example | No suffix | package main | Standalone demo programs |
| Test utilities | *_test.go | package testutil | Shared test helpers |
Requirements and compatibility
Written for: Claude Code, OpenAI Codex
Works with: Claude Code, Claude apps, OpenAI Codex, GitHub Copilot, Cursor, Gemini CLI, Kiro, OpenCode, Goose, Amp, Roo Code, JetBrains Junie, Factory Droid, Devin (ex-Windsurf), Mistral Vibe, OpenHands, Letta
“Works with” means the tool reads the open Agent Skills format; a skill written for one tool may use features others lack.
Needs: Declares allowed tools, Claude Code frontmatter
The author says: Designed for Claude Code, Codex or similar harness, and for projects using Golang.
Security
No issues found by our static scan· No issues found
A static scan is not a guarantee. Skills are third-party content: review a skill before you let an agent use it.
Attribution and licence
- Created by
- samber
- Publisher
- Samuel Berthe (Community)
- Distributed by
- Samuel Berthe
- Source
- samber/cc-skills-golang · skills/golang-project-layout · commit bb1d43d
- Licence
- MIT License (redistribution allowed)
- LICENSE (added by AutoGineer from LICENSE)
- ATTRIBUTION.md (written by AutoGineer)
- Synced
AutoGineer is not affiliated with or endorsed by samber or Samuel Berthe.
Download ZIP
The ZIP holds the skill’s files, its licence files and an ATTRIBUTION.md. Download golang-project-layout.zip