When to Avoid the `/src` Directory in Go Projects: Best Practices Explained

You should avoid adding a top-level src folder to Go modules because it creates unnecessary nesting, clashes with $GOPATH workspace conventions, and provides no functional advantage in the module-aware era.

The golang-standards/project-layout repository explicitly warns against using a /src directory in modern Go projects. According to the project's README.md, this pattern—borrowed from Java—offers little benefit and actively causes confusion with Go's workspace and module systems. Understanding when to avoid the /src directory in Go projects ensures your repositories remain idiomatic and compatible with standard tooling.

Why the /src Directory Is Discouraged in Go

According to lines 891–894 of README.md in the golang-standards/project-layout repository, the Go community generally recommends against top-level src folders. The document outlines three primary reasons this anti-pattern persists and why it should be eliminated.

Legacy Java Conventions vs. Go Workspaces

A src folder represents a legacy Java convention that does not translate to Go's workspace model. As documented in README.md lines 891–894, Go already provides a clear workspace layout via $GOPATH (or, with modules, requires no workspace at all). Duplicating this structure inside a project adds unnecessary nesting without improving organization.

Naming Collisions with $GOPATH/src

Using src creates confusing path collisions. Lines 895–896 of README.md explain that if a project contains its own src folder while residing in $GOPATH/src, the full path becomes …/src/your_project/src/.... This redundancy is noisy and misleading, making navigation and import path reasoning unnecessarily complex.

Modules Eliminate Workspace Structuring Needs

Since Go 1.11, modules allow code to live anywhere outside $GOPATH, rendering dedicated src directories obsolete. Lines 894–896 of README.md note that adding src provides no functional advantage while hurting readability and tooling integration. The module system resolves packages relative to the go.mod file location, not a fixed workspace root.

Instead of nesting code under src/, place packages directly under the repository root or purpose-specific directories. This flat structure aligns with standard Go tooling expectations and simplifies import paths.

The following layout demonstrates the recommended structure:

myapp/
├─ cmd/                # entry-point binaries

│   └─ myapp/
│       └─ main.go
├─ internal/           # private packages

│   └─ auth/
│       └─ auth.go
├─ pkg/                # public libraries

│   └─ utils/
│       └─ math.go
├─ go.mod
└─ README.md

Contrast this with the discouraged approach:

myapp/
├─ src/                # ← unnecessary nesting

│   ├─ cmd/
│   │   └─ myapp/
│   │       └─ main.go
│   ├─ internal/
│   │   └─ auth/
│   │       └─ auth.go
│   └─ pkg/
│       └─ utils/
│           └─ math.go
├─ go.mod
└─ README.md

To convert an existing project, simply move the contents of src/ one level up and delete the empty folder. All import paths remain identical because Go modules resolve packages relative to the module root defined by go.mod.

Where to Place Code Instead of /src

The golang-standards/project-layout repository defines specific directories for organizing code that replace the monolithic src approach.

cmd/ for Entry Points

Executable entry points belong in cmd/. As detailed in cmd/README.md, each application should have its own subdirectory under cmd/, such as cmd/myapp/main.go, keeping main packages isolated and discoverable.

internal/ for Private Packages

Private application code should reside in internal/. According to internal/README.md, packages under this directory are protected by the Go compiler, preventing import by code outside the module boundary. This provides better encapsulation than a generic src folder.

pkg/ for Public Libraries

Public libraries intended for external use belong in pkg/. The pkg/README.md documentation describes this directory as the location for versioned, stable packages that other projects may import. Placing these directly under pkg/ rather than src/pkg/ eliminates redundant path segments.

Summary

  • Avoid top-level src directories in Go modules to prevent unnecessary nesting and path confusion with $GOPATH/src.
  • Use modules-aware layout by placing code directly under cmd/, internal/, or pkg/ according to visibility and purpose.
  • Migrate legacy projects by moving src/ contents to the repository root; import paths remain unchanged due to module-relative resolution.
  • Follow golang-standards/project-layout guidelines documented in README.md lines 891–896 to ensure idiomatic repository structure.

Frequently Asked Questions

Is it ever okay to use a src directory in Go?

Only at the workspace level as $GOPATH/src, never inside individual modules. According to golang-standards/project-layout, adding src to a project repository creates the problematic …/src/project/src/ path structure and offers no benefits in the module era.

How do I migrate an existing project that uses /src?

Move all directories currently inside src/ up to the repository root, then delete the empty src folder. Update your go.mod if necessary, though import paths typically remain valid since modules resolve from the root containing go.mod. Verify builds with go build ./... to ensure all package references resolve correctly.

Does using /src break Go modules?

While modules may still function technically, using /src breaks community conventions and tooling expectations. As noted in README.md lines 895–896, the redundant nesting confuses developers familiar with standard layouts and complicates integration with CI/CD systems expecting canonical structures.

What if my organization requires a src folder for policy reasons?

Challenge the requirement by demonstrating that Go modules (since version 1.11) operate independently of $GOPATH and do not benefit from additional src nesting. The golang-standards/project-layout documentation explicitly states this pattern is a legacy Java carryover inappropriate for Go's module system, making it a poor fit for modern Go development standards.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →