Question
I am building a Go project with multiple files and want to organize it correctly during development.
If my code belongs to a single package called mypack, I assume I should place all .go files for that package inside a mypack directory.
However, I also want to try the package while developing it, which means I need a separate file that declares package main so I can run something like:
package main
import "mypack"
func main() {
// try mypack here
}
What is the standard way to organize a Go project in this situation?
Should I create a separate main program for testing the package manually?
Do I need to run go install mypack every time I want to try the code, or is there a better development workflow?
Short Answer
By the end of this page, you will understand how Go projects are commonly organized using packages and executable programs, why package main should usually be kept separate from reusable library code, and how to test or run your code during development without reinstalling everything each time.
Concept
In Go, project organization is built around packages.
A package is a directory of .go files that all declare the same package name, except for special test files. If you are writing reusable code, that code should usually live in its own package directory such as:
mypack/
Inside that directory, your files might look like this:
// file1.go
package mypack
// file2.go
package mypack
If you also want an executable program that uses that package, that program should normally live in a different directory and use package main.
Why? Because in Go:
- A single directory normally represents one package.
- Files in the same directory must use the same package name.
package maincreates an executable program.- Other package names create reusable libraries.
So your reusable code and your runnable app are usually separated.
This matters because real Go projects often contain:
- one or more reusable packages
- one or more command-line programs
- test files
- sometimes example programs
A clean structure makes it easier to:
- run code during development
- write tests
- reuse packages in other programs
- keep executable code separate from library logic
Mental Model
Think of a Go package as a toolbox and package main as a worker using the toolbox.
- The toolbox contains reusable tools: functions, types, and methods.
- The worker picks up those tools and uses them to do a job.
You do not usually store the worker inside the toolbox.
In the same way:
mypackshould contain the reusable logic.mainshould live separately and call intomypack.
Tests are like a checklist for the toolbox. They live alongside the toolbox so you can quickly verify that each tool still works.
Syntax and Examples
The key rule is: one directory, one package.
Basic package structure
project-root/
go.mod
mypack/
math.go
format.go
// mypack/math.go
package mypack
func Add(a, b int) int {
return a + b
}
// mypack/format.go
package mypack
func Name() string {
return "mypack"
}
Separate runnable program
project-root/
go.mod
mypack/
math.go
cmd/
tryapp/
main.go
// cmd/tryapp/main.go
package main
import (
"fmt"
"project-root/mypack"
)
func main() {
fmt.Println(mypack.Add(2, ))
}
Step by Step Execution
Consider this project:
project-root/
go.mod
mypack/
greet.go
cmd/
tryapp/
main.go
// mypack/greet.go
package mypack
func Greet(name string) string {
return "Hello, " + name
}
// cmd/tryapp/main.go
package main
import (
"fmt"
"project-root/mypack"
)
func main() {
message := mypack.Greet("Sam")
fmt.Println(message)
}
If you run:
go run ./cmd/tryapp
here is what happens:
- Go finds the
mainpackage in./cmd/tryapp. - It sees that
main.goimportsproject-root/mypack. - It loads the source files inside the
mypackdirectory.
Real World Use Cases
This package-and-main separation is used in many real Go projects.
Command-line tools
A CLI tool often has:
- reusable logic in internal or package directories
- a small
main.goincmd/toolname
Example:
- parsing files in a package
- calling that package from a CLI command
Web services
A web app may separate:
- HTTP handlers
- business logic
- database access
- executable startup code
The main package sets up the server, while packages contain reusable logic.
SDKs and libraries
If you are building code for reuse by other Go programs, the package should be clean and independent from any particular executable.
Experiments and local demos
During development, many developers create a small runner program to manually try a package without mixing demo code into the package itself.
Real Codebase Usage
In real codebases, developers usually avoid putting temporary testing code directly into a library package.
Common patterns include:
Small cmd/... programs
A project may include one or more runnable programs:
cmd/
api-server/
worker/
debug-tool/
Each directory contains a separate main package.
Unit tests for behavior
Instead of manually trying everything through main, developers write tests:
- unit tests for functions
- table-driven tests for multiple cases
- benchmarks for performance-sensitive code
Example programs
Sometimes developers add examples for documentation or learning:
func ExampleAdd() {
fmt.Println(Add(2, 3))
// Output: 5
}
Guarding library boundaries
A good library package usually avoids:
- reading command-line flags directly
- printing too much directly to stdout
- hardcoding app-specific behavior
That logic belongs in main or in higher-level application code.
Common Mistakes
Mixing package main and another package in one directory
This is one of the most common mistakes.
Broken example:
// mypack/file1.go
package mypack
// mypack/trypack.go
package main
This does not work because a directory should not contain files from different packages in normal use.
Using go install as the main development workflow
Beginners sometimes think they must install after every change.
Usually better:
go run ./cmd/tryapp
go test ./...
Use go install when you want the executable installed for repeated use.
Putting too much logic in main
Broken style:
package main
import "fmt"
func main() {
// all logic here
fmt.Println( + )
}
Comparisons
| Concept | Purpose | Typical Location | Runnable? |
|---|---|---|---|
package mypack | Reusable library code | mypack/ | No |
package main | Executable program | cmd/appname/ or project root | Yes |
*_test.go | Automated tests | Same directory as package | Only through go test |
go run vs go build vs go install
Cheat Sheet
Core rules
- One directory usually contains one package.
- Reusable code goes in a non-
mainpackage. - Executable code goes in
package main. - Keep
mainin a separate directory from library code. - Use
*_test.gofiles for tests.
Common structure
project-root/
go.mod
mypack/
file1.go
file2.go
mypack_test.go
cmd/
tryapp/
main.go
Common commands
go run ./cmd/tryapp
go test ./...
go build ./...
go install ./cmd/tryapp
When to use what
- Use
go runto quickly execute your app. - Use
go testto test package behavior. - Use
go buildto verify compilation. - Use
go installwhen you want the executable installed.
Remember
- Do not mix
package mainandpackage mypackin one directory. - Import paths come from module paths.
FAQ
Do I need go install every time I change my Go package?
No. During development, use go run for executable programs and go test for package tests. go install is usually for installing a finished command.
Can I put package main and package mypack in the same folder?
Normally no. Go expects source files in a directory to belong to the same package.
How do I manually try a package while developing it?
Create a small separate program with package main, usually in a directory such as cmd/tryapp, and run it with go run.
Should I test with a manual runner or with go test?
Use both when useful. Manual runners help you experiment, while go test gives repeatable automated checks.
Where should Go test files go?
Usually in the same directory as the package they test, with names ending in _test.go.
What is the purpose of the cmd directory in Go projects?
It is a common convention for storing executable entry points. Each subdirectory usually contains one package.
Mini Project
Description
Build a small Go project with a reusable package and a separate runnable program. This demonstrates the standard development layout: package code in one directory, a main package in another directory, and tests alongside the package code.
Goal
Create a reusable greet package, run it from a small command-line program, and verify it with a unit test.
Requirements
- Create a package that exposes a function to build a greeting message.
- Create a separate
mainprogram that imports the package and prints a greeting. - Add at least one automated test for the package.
- Run the program with
go runinstead of reinstalling after every change.
Keep learning
Related questions
Automatic Build Versioning in Go: Embed Incrementing Build Numbers
Learn how to add automatic build versioning in Go using linker flags, build metadata, CI counters, and Git-based version values.
Blank Identifier Imports in Go: What `_` Means in an Import Statement
Learn what `_` means in a Go import, why blank identifier imports run package init code, and when to use them safely.
Calling Functions Across Files in the Same Go Package
Learn how Go uses packages across multiple files, why functions may appear undefined, and how to organize code correctly.