Question

How to Run a Go Program with Multiple Files in the Same Package

gopackage

Question

I have a Go program with a main.go file in the main package. I want to move some code into another file while keeping both files in the same package, rather than creating a separate package.

My goal is to use a directory structure like this:

foo/
├── main.go
└── bar.go

bar.go:

package main

import "fmt"

func Bar() {
    fmt.Println("Bar")
}

main.go:

package main

func main() {
    Bar()
}

I want main.go to call Bar() from bar.go. However, when I run:

go run main.go

I get this error:

# command-line-arguments
./main.go:4:2: undefined: Bar

How can I split a Go main package into multiple files and run the program without this error?

Short Answer

By the end of this page, you will understand how Go treats multiple files in the same package, why go run main.go fails in this case, and how to correctly run all files in a package together. You will also learn how this works in real Go projects and how to avoid common package and file-organization mistakes.

Concept

In Go, a package can be made up of multiple .go files in the same directory. If those files all declare the same package name, such as package main, they are compiled together as one unit.

That means this is completely valid:

  • main.go contains main()
  • bar.go contains helper functions
  • both files use package main
  • both files live in the same folder

The important detail is how you run the program.

When you execute:

go run main.go

Go only compiles and runs that one file. It does not automatically include other files from the same directory. Since bar.go is not part of that command, Bar() is unknown, so you get undefined: Bar.

To run all files in the package, you should run the package, not just one file:

go run .

or explicitly list both files:

go run main.go bar.go

This matters in real programming because Go organizes code around packages, not around one giant source file. Splitting code into multiple files improves readability and maintenance, but you must still compile the package correctly.

Mental Model

Think of a Go package like a folder of recipe cards that together describe one meal.

  • main.go is one card
  • bar.go is another card
  • both belong to the same meal because they are in the same folder and have the same package name

If you say, "Use only this one card," Go only sees main.go. If that card refers to instructions written on bar.go, it fails.

If you say, "Use the whole folder," Go reads all matching cards together and everything works.

So the key idea is:

  • go run main.go = run one file
  • go run . = run the whole package in the current directory
Take Quiz

Syntax and Examples

In the same directory, files with the same package name are part of the same package.

Basic syntax

main.go

package main

func main() {
    Bar()
}

bar.go

package main

import "fmt"

func Bar() {
    fmt.Println("Bar")
}

Correct ways to run it

Run the whole package in the current directory:

go run .

Or list the files explicitly:

go run main.go bar.go

Output

Bar

Why this works

Both files:

  • are in the same directory
  • use package main
  • are compiled together when you run the package

Another beginner-friendly example

main.go

package main

func main() {
    greet("Ada")
}

greet.go

package main

import "fmt"

func greet(name string) {
    fmt.Println("Hello,", name)
}

Run it with:

go run .

This prints:

Hello, Ada

The function can be lowercase here because it is used inside the same package. In Go, lowercase names are package-private and uppercase names are exported for use from other packages.

Step by Step Execution

Consider this program:

main.go

package main

func main() {
    Bar()
}

bar.go

package main

import "fmt"

func Bar() {
    fmt.Println("Bar")
}

What happens with go run main.go

  1. Go reads only main.go because that is the only file you asked it to run.
  2. It sees a call to Bar() inside main().
  3. It looks for a definition of Bar() in the compiled input.
  4. bar.go was not included.
  5. Compilation fails with:
undefined: Bar

What happens with go run .

  1. Go reads the current directory as a package.
  2. It collects all .go files in that package.
  3. It finds both main.go and bar.go.
  4. It compiles them together.
  5. main() calls Bar() successfully.
  6. The program prints:
Bar

Key takeaway

The difference is not the code. The difference is what Go is compiling.

Real World Use Cases

Splitting one Go package across multiple files is very common.

Common scenarios

  • CLI tools: main.go starts the app, while other files handle flags, validation, and output.
  • Small web servers: one file for routes, one for handlers, one for configuration.
  • Data scripts: one file for input parsing, another for processing, another for reporting.
  • Prototypes: keep everything in package main at first, then refactor later if code becomes reusable.

Example structure for a small CLI

myapp/
├── main.go       # program entry point
├── config.go     # config loading
├── output.go     # printing helpers
└── validate.go   # input checks

All of these can stay in package main if the code is only for that application.

Why developers do this

  • easier to read than one very long file
  • related code can be grouped together
  • no need to create a new package too early
  • makes later refactoring simpler
Take Quiz

Real Codebase Usage

In real Go projects, developers often start with multiple files in one package and split into separate packages only when reuse or clearer boundaries become necessary.

Common patterns

Keep main.go small

A common pattern is to keep main.go focused on startup only:

package main

func main() {
    run()
}

Then put run() and other logic in other files.

Use helper files by responsibility

Examples:

  • config.go
  • server.go
  • handlers.go
  • db.go
  • util.go

Use guard clauses and validation

A file like validate.go might contain checks used by main.go:

package main

import "errors"

func validateName(name string) error {
    if name == "" {
        return errors.New("name is required")
    }
    return nil
}

Early returns for startup flow

package main

import "fmt"

func run() error {
    fmt.Println("starting app")
    return nil
}

func main() {
    if err := run(); err != nil {
        panic(err)
    }
}

This pattern keeps the application organized while still using a single package.

When to create a separate package

Move code into another package when:

  • it is reusable in multiple parts of the project
  • it has a clear boundary or responsibility
  • the package helps readability more than it adds complexity

Common Mistakes

1. Running only one file

Broken command:

go run main.go

If main.go depends on functions in other files, this fails.

Use instead:

go run .

or:

go run main.go bar.go

2. Mixing package names in one directory

Broken example:

main.go

package main

func main() {
    Bar()
}

bar.go

package helpers

func Bar() {}

This does not work in the same folder as one package build target.

To keep files together as one package, they must use the same package name.

3. Thinking uppercase is required inside the same package

This is valid too:

package main

func bar() {}

and:

package main

func main() {
    bar()
}

Uppercase names are only needed when you want to export something to another package.

4. Putting files in different directories and expecting one package automatically

In Go, directory structure matters. Files in different folders are normally different packages.

5. Forgetting that _test.go files are special

Test files are used by go test, not normal go run builds.

6. Using separate packages too early

Beginners sometimes create a new package just to split one file. If the code is only used by the current app, multiple files in package main may be enough.

Comparisons

Running one file vs running a package

CommandWhat Go includesGood forResult in this case
go run main.goOnly main.goVery small single-file programsFails because Bar() is missing
go run main.go bar.goExactly those filesExplicit file-based runsWorks
go run .All Go files in the current packageNormal project workflowWorks

Same package vs separate package

ApproachWhen to use itProsCons
Multiple files in package mainApp-specific codeSimple, easy to startCan grow messy if overused
Separate packageReusable or clearly separate logicBetter structure, easier reuseMore setup and imports

Exported vs unexported names

Name styleExampleVisible where?
UppercaseBarSame package and other packages
LowercasebarSame package only

If both files are in package main, either uppercase or lowercase can work depending on whether you need exporting.

Take Quiz

Cheat Sheet

Quick rules

  • Files in the same folder with the same package name belong to one package.
  • go run main.go runs only main.go.
  • go run . runs the whole package in the current directory.
  • go run main.go bar.go runs exactly those files together.
  • Functions in the same package can call each other across files.
  • Uppercase names are for exported identifiers; lowercase names are package-private.

Correct setup

foo/
├── main.go
└── bar.go

Both files:

package main

Run with:

go run .

Common error

undefined: Bar

Usually means the file containing Bar() was not included in the build.

Good default habit

For a multi-file Go app, use:

go run .

If you want to build instead of run

go build .

This builds the whole package in the current directory.

FAQ

Why does go run main.go not see functions in other files?

Because that command only compiles main.go. It does not automatically include other files in the package.

What is the correct command for a multi-file Go program?

Usually:

go run .

This tells Go to run the whole package in the current directory.

Can I keep multiple files in package main?

Yes. This is normal for small and medium applications.

Do I need to create a separate package just to split code into files?

No. You can split code into multiple files within the same package.

Should the function be Bar or bar?

If it is only used inside the same package, either can work. Use bar for package-private helpers and Bar only when exporting is needed.

Can I run specific files instead of the whole package?

Yes:

go run main.go bar.go

But in real projects, go run . is usually simpler.

What if my files are in different folders?

Then they are usually different packages, and you must import one package from another rather than expecting them to compile together.

Take Quiz

Mini Project

Description

Build a small command-line Go program split across multiple files in the same main package. This demonstrates the exact pattern used when a program becomes too large for a single main.go file, but is still simple enough that creating separate packages is unnecessary.

Goal

Create a multi-file Go program that prints a greeting and a status message by calling functions defined in different files of the same package.

Requirements

  1. Create at least three Go files in the same directory.
  2. Put all files in package main.
  3. Define main() in main.go.
  4. Move helper functions into other files.
  5. Run the program using the whole package, not just one file.
Take Quiz

Keep learning

Related questions

View more