# Golang Project Layout

> Design, scaffold, or restructure a Go repository around modules, build targets, package ownership, visibility, tests, generated code, and deployment boundaries. Use for new project layout, monorepos, package splits, module splits, or import-path migrations.

- Skill: `reagin/golang-project-layout` (Agent Skill)
- Install (CLI): `npx skillmds@latest add reagin/golang-project-layout`
- Raw SKILL.md: https://api.skillmd.com/api/skills/reagin/golang-project-layout/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- License: MIT
- Author: reagin (https://skillmd.com/u/reagin)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/reagin/golang-project-layout

---


# Go Project Layout

Let dependency direction and ownership shape directories. Go does not require a single repository layout.

## Inspect before proposing structure

Read go.mod, go.work, executable entry points, public imports, generated-code configuration, build and deployment files, tests, and repository instructions. Identify:

- one module or multiple independently versioned modules;
- libraries versus executable targets;
- public packages consumed outside the module;
- code that must be hidden from external importers;
- shared domain concepts versus incidental reuse;
- generated, embedded, migration, fixture, and deployment artifacts;
- compatibility constraints on import paths.

Do not restructure a working repository for visual symmetry. Moving a Go package changes its import path and can be a breaking API change.

## Choose boundaries

Prefer a shallow structure until real ownership or dependency boundaries justify more depth.

- Keep one main package per executable target. A cmd directory is useful for multiple commands or when it matches repository convention, but is not mandatory for a single small program.
- Use internal when the compiler-enforced import boundary is valuable. Do not put everything under internal by habit.
- Public reusable packages should have a coherent API and domain name. A top-level pkg directory is optional and should not be introduced as ceremony.
- Avoid generic common, shared, helpers, or utils packages. Place behavior with the domain that owns it; extract only after a stable shared concept appears.
- Keep application composition near the executable while domain and infrastructure packages remain independently testable where useful.
- Keep generated code visibly separated or named according to the generator, and never hand-edit it.
- Place migrations, schemas, templates, and embedded files where ownership and build paths remain obvious.

Package names should be concise and describe what callers receive, not repeat the repository or implementation mechanism.

## Select module strategy

Use one module when code releases and evolves together and independent versioning offers no value. Multiple modules can be justified by independently consumed APIs, distinct release lifecycles, access boundaries, or incompatible dependency policies, but they increase testing, tagging, replace, and workspace complexity.

A go.work file coordinates local development; it does not replace testing each module as an external consumer would see it. Decide whether the workspace is committed or developer-local based on repository policy.

Do not create nested modules merely to hide dependency conflicts.

## Tests and examples

Keep ordinary tests beside the package they exercise. Choose the same package for internal behavior access or an external test package for consumer-level API validation. Use internal test helpers or clearly owned fixture directories rather than a global test utility dumping ground.

Place integration or end-to-end suites separately only when they require distinct orchestration, build tags, credentials, or runtime. Keep golden files and testdata under the owning package so Go tooling ignores them as packages.

Executable examples belong where users can discover and run them, but avoid an examples tree that duplicates untested production code.

## Plan a safe restructure

For an existing repository:

1. Map current importers and public paths.
2. Propose the smallest boundary change that solves the stated problem.
3. Separate mechanical moves from behavioral edits where practical.
4. Update package declarations, imports, generators, embeds, tests, scripts, and documentation.
5. Preserve public paths with a deliberate compatibility layer only when compatibility is required.
6. Verify each module and executable independently.
7. Remove obsolete directories and temporary forwarding packages when no compatibility requirement remains.

Do not mix a broad architecture rewrite into a layout request unless the user selects that scope.

## Scaffolding checklist

Create only files with immediate purpose:

- correct module path and intended Go directive;
- minimum executable or package entry points;
- focused package boundaries;
- tests for the first behavior;
- build, CI, configuration, license, and documentation files only when requested or required by the repository;
- ignore rules based on actual generated artifacts, not a copied global template.

Do not add Makefiles, Dockerfiles, environment examples, configuration frameworks, or dependency-injection systems as placeholders.

## Verification

Run gofmt, package listing, compilation, tests, and repository-specific checks. Search for stale import paths and update generated-code commands and documentation. If public import paths changed, call out the compatibility impact explicitly.

