← Back to Go Course | Chapter 1: Setup & Basics | Lesson 6 of 7

Go Project Workspace Structure

A Go project's folder layout is like organizing a toolbox -- each drawer (folder) has a clear job so anyone can find what they need.

A Minimal Layout

The simplest possible Go project is just a go.mod file and a main.go in the same directory. As a project grows, code is split into subdirectories, each subdirectory becoming its own importable package named after its folder.

Example: A Minimal Layout

markup
// Every Go file belongs to a package; main builds an executable
package main

// Import the fmt package
import "fmt"

// main is where the program starts running
func main() {
	// Print the values followed by a newline
	fmt.Println("myapp/")
	// Print the values followed by a newline
	fmt.Println("  go.mod")
	fmt.Println("  main.go")
}

Organizing Packages by Folder

Each directory containing .go files (other than the root) typically represents one package, imported by its path relative to the module root, such as github.com/example/myapp/utils.

This convention keeps related code together and makes the import graph easy to follow just by looking at the file tree.

Note: Package names are conventionally short, lowercase, and match the folder name.

Example: Organizing Packages by Folder

markup
// Every Go file belongs to a package; main builds an executable
package main

// Import the fmt package
import "fmt"

// main is where the program starts running
func main() {
	// Short declaration: create layout and infer the type
	layout := []string{"myapp/go.mod", "myapp/main.go", "myapp/utils/strings.go"}
	// Loop over layout; the blank identifier _ ignores the index
	for _, path := range layout {
		// Print the values followed by a newline
		fmt.Println(path)
	}
}

The internal/ Convention

Go treats any package inside a directory named internal specially: it can only be imported by code rooted at the parent of that internal directory.

This is the standard way to mark packages as private implementation details that outside modules should not depend on.

Example: The internal/ Convention

markup
// Every Go file belongs to a package; main builds an executable
package main

// Import the fmt package
import "fmt"

// main is where the program starts running
func main() {
	// Print the values followed by a newline
	fmt.Println("myapp/internal/auth can only be imported from within myapp")
}

Where Tests Live

Go test files sit right next to the code they cover and are named with a _test.go suffix, such as strings_test.go alongside strings.go.

The 'go test' tool automatically finds and runs every _test.go file in a package, so there's no separate test-discovery configuration needed.

Example: Where Tests Live

markup
// Every Go file belongs to a package; main builds an executable
package main

// Import the fmt package
import "fmt"

// main is where the program starts running
func main() {
	// Print the values followed by a newline
	fmt.Println("utils/strings.go")
	// Print the values followed by a newline
	fmt.Println("utils/strings_test.go")
}
Related Topics
{# common_mistakes/chapter_summary/browser_support: on Hindi pages the view already swaps in the hi_ translation fields (or blanks these out if untranslated), so this renders correctly for both languages without a lang_code check here. #}
Common Mistakes
  1. Putting all code in package main inside one giant file instead of splitting reusable logic into separate packages.
  2. Creating a top-level src folder out of old GOPATH habit, which modern Go modules don't require or expect.
  3. Mixing test files, main application code, and documentation with no consistent naming, making 'go build ./...' behave unpredictably.
Chapter Summary
  • A typical Go project has a go.mod at its root and a main.go (or a cmd/ directory) as the entry point.
  • Reusable logic is organized into small, focused packages, each in its own directory.
  • The 'internal/' directory name has special meaning: it restricts imports to within the module.
  • Test files live alongside the code they test, named with a _test.go suffix.
🔒

Chapter Quiz — Complete all 7 topics to unlock

0/7 topics done

Complete these topics first:

Login to run this code

C/C++/Java/PHP execution requires a free account. Your code is saved — you'll land right back in the editor after logging in.