golang-standards/project-layoutis the community-maintained reference for conventional Go project directory structure. It defines a set of directory names — each with aREADME.mdexplaining its purpose and when to use it — that Go developers can treat as a template when starting a new application, service, or library. No application code is prescribed; the repository IS the documentation. It ships in the canonical EnglishREADME.mdplus 19 translations, making the conventions accessible to the global Go community.
What's in This Collection
| Item | Path(s) | Description |
|---|---|---|
| Canonical English reference | README.md |
Primary layout guide — describes every directory, its purpose, real-world usage notes, and when to skip |
| Translations | README_be.md, README_bn.md, README_es.md, README_fa.md, README_fr.md, README_hi.md, README_id.md, README_it.md, README_ja.md, README_ko.md, README_ptBR.md, README_ro.md, README_ru.md, README_tr.md, README_ua.md, README_vi.md, README_zh-CN.md, README_zh-TW.md, README_zh.md |
19 community-maintained translations of the main guide |
| Directory stub READMEs | api/README.md, assets/README.md, cmd/README.md, configs/README.md, deployments/README.md, docs/README.md, examples/README.md, githooks/README.md, init/README.md, internal/README.md, pkg/README.md, scripts/README.md, test/README.md, tools/README.md, web/README.md, website/README.md |
Per-directory descriptions; each explains that directory's role and links to real-world examples in major Go projects |
| Placeholder module file | go.mod |
Declares module github.com/YOUR-USER-OR-ORG-NAME/YOUR-REPO-NAME with go 1.19 — a copy/paste starting point |
| Placeholder directory stubs | cmd/_your_app_/, internal/app/_your_app_/, internal/pkg/_your_private_lib_/, pkg/_your_public_lib_/ |
.keep files holding the directory shape; rename or delete in actual projects |
| Root config starters | Makefile, .editorconfig, .gitignore, .gitattributes |
Minimal top-level files included as a starter; not prescriptive |
| License | LICENSE.md |
Informal one-line "Hacker license!" — not a standard OSI license |
Note
This repository contains zero application source code —
total_source_chars: 0. Every file is documentation, configuration metadata, or an empty directory placeholder. When you clone it as a template, you replace the stubs with your own code.
How to Read / Use This
Intended audience
Go developers starting a new project (application, service, library) who want a community-backed directory convention rather than inventing structure from scratch. Architects reviewing an existing codebase against common Go conventions also use this as a benchmark.
How to navigate
The collection is not linear. Read the canonical README.md top to bottom once to understand the full layout and the rationale for each directory. After that, treat the per-directory README.md files as reference cards — jump to whichever directory you're deciding about.
Entry points by reader type:
| Reader | Start here |
|---|---|
| Starting a new Go application | README.md — read the "Go App Directories" section first (/cmd, /internal, /pkg) |
| Adding a service API | api/README.md |
| Setting up CI/CD or container deployments | deployments/README.md |
| Adding scripts or a build system | scripts/README.md and Makefile at repo root |
| Hosting project documentation | docs/README.md and website/README.md |
| Non-English readers | The matching README_*.md translation at repo root |
Tip
You do not need to use every directory in the layout. The README explicitly calls out which directories are optional and which are used only by specific project types (e.g.,
/webis only for web applications,/initonly for projects that ship service manager configs).
Using the repo as a project template
The repository is designed to be cloned and stripped down:
git clone https://github.com/golang-standards/project-layout.git my-new-project
cd my-new-project
rm -rf .git
git init
After cloning, delete every directory you don't need and rename the _your_app_ / _your_public_lib_ / _your_private_lib_ placeholder stubs to match your actual package names.
Important
Update
go.modimmediately after cloning. The placeholdermodule github.com/YOUR-USER-OR-ORG-NAME/YOUR-REPO-NAMEwill cause build failures if left unchanged. Replace it with your real module path before writing any Go code.
Section Walkthroughs
Go Application Directories
These are the most important directories in the layout — the directories any Go application is likely to need.
/cmd
The entry point for each binary in the repository. Each subdirectory of /cmd maps 1:1 to an executable name (e.g., cmd/myapp/ produces the myapp binary). The cmd/_your_app_/ stub in this repo is a .keep placeholder — rename it to your binary name.
The code inside each /cmd subdirectory should be minimal: import and call functions from /internal and /pkg, but avoid putting significant logic here. This keeps the entry point thin and testable business logic in proper packages.
Tip
It is common to have multiple binaries in one repo (e.g.,
cmd/server/,cmd/cli/,cmd/worker/). Each gets its own subdirectory under/cmdand its ownmain.go.
/internal
Private application and library code. The Go compiler enforces this privacy: no external module can import from your /internal packages. This is the primary location for business logic, domain models, and application-specific code that should not become a public API.
The layout further subdivides /internal:
internal/app/_your_app_/— application-specific logic that is not shared across binariesinternal/pkg/_your_private_lib_/— shared private library code reused across multiple binaries in the same repo
/pkg
Library code that is safe and intentional to share with external applications. Packages placed here declare "this is a public API — other repos may import and depend on it." Use this directory only for code you want to be importable externally. The pkg/_your_public_lib_/ stub is a .keep placeholder.
Warning
Do not put everything in
/pkgjust to avoid importing from/internal. If code is internal to your application, put it in/internaland let the compiler enforce the boundary. Misusing/pkgas a catch-all makes API guarantees meaningless.
Service Application Directories
/api
Protocol and schema definitions: OpenAPI/Swagger specs, JSON Schema files, Protocol Buffer definitions (.proto), Thrift IDL files. The descriptions for the API live here, not the server implementation.
Web Application Directories
/web
Web application specific components, divided into three conventional subdirectories:
web/app/— single-page application (SPA) JavaScript frontend; the.keepstub marks the directoryweb/static/— static assets served directly (CSS, images, fonts); the.keepstub marks the directoryweb/template/— server-side Go templates (html/template,text/template); the.keepstub marks the directory
The web/README.md describes the purpose of this top-level grouping.
Common Application Directories
/configs
Configuration file templates or default configuration files. Specifically, this is where confd or consul-template template files live. For projects shipping a default config.yaml or environment-specific overrides, put them here.
/init
System init (systemd, upstart, sysv) and process manager/supervisor (runit, supervisord) configuration files. Used only when a project ships service definitions intended to be installed on a server.
/scripts
Scripts that perform build, install, analysis, and other operations. The directory keeps the root-level Makefile small and simple by delegating longer operations to scripts.
scripts/
├── build.sh
├── test.sh
└── lint.sh
Real-world examples cited in scripts/README.md:
kubernetes/helm—scripts/cockroachdb/cockroach—scripts/hashicorp/terraform—scripts/
/build
Not represented by a stub in this repo, but described in the main README: packaging and Continuous Integration. Put cloud, container, OS packaging configs (Dockerfile, RPM specs, .deb manifests) in /build/package/. Put CI configs for Travis CI, CircleCI, Drone, etc. in /build/ci/.
/deployments
IaaS, PaaS, system and container orchestration deployment configs. Includes docker-compose, Kubernetes/Helm charts, Mesos, Terraform, Bosh manifests. Some repos use /deploy/ instead.
Note
The community actively discusses where to place Helm charts (GitHub issue #137). The
/deploymentsdirectory is the layout's answer, though some large projects use a dedicated/chartssubdirectory within it.
/test
Additional external test apps and test data. You can structure /test freely. For larger projects it makes sense to use /test/data or /test/testdata — Go ignores any directory beginning with . or _, giving flexibility in naming test data.
Real-world example cited in test/README.md: openshift/origin/test (with test data in /testdata subdirectory).
Other Directories
/docs
Design documents, user documentation, and architectural decision records — material beyond what godoc auto-generates from source comments. Place design specs, ADRs, user-facing guides, and diagrams here.
Real-world examples cited in docs/README.md:
gohugoio/hugo/docsopenshift/origin/docsdapr/dapr/docs
/tools
Supporting tools for the project that are not meant to be user-facing binaries. Tools here can import code from /pkg and /internal.
Real-world examples cited in tools/README.md:
istio/istio/toolsopenshift/origin/toolsdapr/dapr/tools
/examples
Example applications and usage demonstrations for public libraries or applications. Intended to show consumers of /pkg how to integrate with your library.
/githooks
Git hooks for the project — scripts invoked by Git before or after events (pre-commit, pre-push, etc.). Developers must install these manually or via a setup script; Git does not install hooks from a repo's githooks/ directory automatically.
/assets
Other repository assets that accompany the code: images, logos, diagrams, and similar binary assets referenced by the README or documentation.
From assets/README.md:
"Other assets to go along with your repository (images, logos, etc)."
/website
Project website data when GitHub Pages is not used. Place your project's static site source here.
/vendor
Not represented as a stub directory, but described in the main README as optional. Contains application dependencies managed with go mod vendor. Modern Go projects use the module cache (GOPATH/pkg/mod) rather than a local /vendor directory; use /vendor if your build environment requires offline or reproducible vendored builds.
Root-Level Files
| File | Purpose |
|---|---|
README.md |
Canonical English layout guide (the primary document) |
README_*.md |
19 community translations |
go.mod |
Placeholder module declaration — module github.com/YOUR-USER-OR-ORG-NAME/YOUR-REPO-NAME, go 1.19 |
Makefile |
Starter build targets; delegates to scripts/ |
.editorconfig |
Code style settings for editors that support it |
.gitignore |
Standard Go gitignore |
.gitattributes |
Git attribute settings |
LICENSE.md |
Contains a single informal line, Hacker license! — not a standard OSI-approved license |
Contributing / Extending
The repository accepts contributions primarily as: additions or corrections to the per-directory README.md files, new translation files (README_*.md), and updates to existing translations. Open issues are actively tracked for translation sync (e.g., issue #274 tracks Simplified Chinese), grammar corrections (issues #284, #271), and content debates (issue #278 on tone).
Note
Translation contributions follow the naming convention
README_{language-code}.md. Language codes used in the repository:be(Belarusian),bn(Bengali),es(Spanish),fa(Farsi),fr(French),hi(Hindi),id(Indonesian),it(Italian),ja(Japanese),ko(Korean),ptBR(Brazilian Portuguese),ro(Romanian),ru(Russian),tr(Turkish),ua(Ukrainian),vi(Vietnamese),zh-CN(Simplified Chinese),zh-TW(Traditional Chinese),zh(Chinese).
When proposing a new directory name or changing existing guidance, open a GitHub issue for community discussion first. The layout is intentionally stable; changes require broad consensus.
FAQ
Q: Do I have to use all these directories?
No. Many of them are optional. Use only the directories your project actually needs. A small library might only need /pkg and a root README.md. A large microservice might use /cmd, /internal, /api, /deployments, and /scripts. Delete what you don't need when using this repo as a template.
Q: Where do I put Helm charts?
Community issue #137 discusses this. The conventional answer is /deployments (or a subdirectory like /deployments/helm/). Some large projects create a top-level /charts directory instead. Neither is wrong; pick one and stay consistent.
Q: Where do I put generated code?
Community issue #283 raises this. There is no single prescribed location. Common patterns are a /gen or /generated subdirectory, or keeping generated files alongside their templates. The layout does not mandate a specific location for generated code.
Q: Where do I put SQL migrations, localization files, or mail templates?
Community issue #11 covers this. The layout does not prescribe a specific location. Common practice is a top-level /migrations directory for SQL migrations, /locales for i18n files, and placing mail templates under /internal or /assets depending on whether they're app-specific or public-facing.
Q: Why use a Makefile?
Community issue #279 asks this. The Makefile at repo root serves as a task runner — make build, make test, make lint — with the actual logic delegated to scripts/. This avoids cross-platform incompatibilities in the root Makefile itself while keeping a single well-known entry point for common operations.
Q: Why are some directories plural and some singular?
Community issues #187 and #218 discuss this. Go's own standard library and most major Go projects use plural for directories containing multiple items (/docs, /scripts, /tools) and singular for those with special toolchain meaning (/cmd, /pkg, /api). The inconsistency reflects organic community convention rather than a deliberate rule.
Q: Where do I put auxiliary tool configuration files (.golangci.yml, buf.gen.yaml, etc.)?
Community issue #256 addresses this. The layout does not prescribe a location. Repository root and /configs are both commonly used. Putting toolchain config at root is most common because many tools look there by default.
Q: How do I debug a project using this structure in VS Code?
Community issue #215 covers this. For a project with binaries in cmd/myapp/, create a VS Code launch configuration in .vscode/launch.json that sets "program": "${workspaceFolder}/cmd/myapp". The .vscode/ directory sits at repo root (it is not prescribed by this layout) and is typically added to .gitignore.
Tip
The
/.vscodedirectory is not part of the golang-standards layout but is safely co-located with it. Add.vscode/to your.gitignoreif the IDE config should not be tracked, or commit it if your team wants a shared debug configuration.
Related Resources
The directory READMEs throughout this repo reference real-world examples from major Go projects. Frequently cited repositories:
| Project | Used as example for |
|---|---|
kubernetes/helm |
/scripts layout |
cockroachdb/cockroach |
/scripts layout |
hashicorp/terraform |
/scripts layout |
openshift/origin |
/scripts, /test, /docs layouts |
gohugoio/hugo |
/docs layout |
dapr/dapr |
/docs, /tools layouts |
istio/istio |
/tools layout |
For Go module conventions referenced by go.mod, see the official Go Modules Reference. For documentation generation from Go source comments, see godoc.