Question

Calling Functions Across Files in the Same Go Package

goundefinedfunc

Question

I am writing a basic Go program that calls a function defined in a different file but within the same package. However, I get an error saying that NewEmployee is undefined.

Here is the code:

// main.go
package main

func main() {
    emp := NewEmployee()
    _ = emp
}
// employee.go
package main

type Employee struct {
    name string
    age  int
}

func NewEmployee() *Employee {
    p := &Employee{}
    return p
}

func PrintEmployee(p *Employee) string {
    return "Hello world!"
}

Why would a function declared in another file of the same package be reported as undefined, and how should this be set up correctly in Go?

Short Answer

By the end of this page, you will understand how Go treats multiple files in the same package, why a function can still appear as undefined, how to compile and run Go code correctly, and how exported and unexported names affect visibility.

Concept

In Go, files that belong to the same package are compiled together. That means a function defined in employee.go should be available in main.go as long as both files are in the same folder and are built together.

In your example, both files use:

package main

So NewEmployee() is visible to main.go without any import.

If Go says undefined: NewEmployee, the problem is usually not the function definition itself. The most common cause is that only one file is being run or built.

For example, if you run:

go run main.go

Go will compile only main.go, not employee.go. Since employee.go is excluded, NewEmployee() does not exist from the compiler's point of view.

Instead, you should run the whole package:

go run .

or:

go build

This tells Go to compile all .go files in the current package directory.

Another important idea is name visibility:

  • Names starting with an uppercase letter are exported.
  • Names starting with a lowercase letter are unexported.

Inside the same package, both exported and unexported names are accessible. Across different packages, only exported names are accessible.

So in your code:

  • NewEmployee is exported
  • Employee is exported
  • name and age are unexported

That is valid, and main.go can still use them because it is in the same package.

One more note: your PrintEmployee function returns a string, so its signature should include string as the return type. Otherwise, the code will not compile.

Mental Model

Think of a Go package like a folder of recipe cards that are all used to make one meal.

  • Each .go file is one recipe card.
  • The package line says which meal that card belongs to.
  • When Go builds the package, it gathers all recipe cards in the same folder and package.

If you only hand Go one card, like main.go, it cannot see the instructions written on employee.go.

So the issue is usually not "the function is in another file". The issue is "that file was not included in the build."

Take Quiz

Syntax and Examples

In Go, functions in the same package can be used directly across files.

Example structure

// main.go
package main

import "fmt"

func main() {
    emp := NewEmployee()
    fmt.Println(emp)
    fmt.Println(PrintEmployee(emp))
}
// employee.go
package main

type Employee struct {
    name string
    age  int
}

func NewEmployee() *Employee {
    return &Employee{name: "Alice", age: 30}
}

func PrintEmployee(p *Employee) string {
    return "Hello world!"
}

How to run it

Run the package, not a single file:

go run .

Why this works

  • Both files are in the same directory.
  • Both files declare package main.
  • go run . includes all files in that package.

If files are in different packages

Then you must import the package and use exported names only.

package employee

type Employee struct{}

func NewEmployee() *Employee {
    return &Employee{}
}
package main

import "myapp/employee"

func main() {
    emp := employee.NewEmployee()
    _ = emp
}

That is a different setup from your original question.

Step by Step Execution

Consider this code:

// main.go
package main

import "fmt"

func main() {
    emp := NewEmployee()
    fmt.Println(PrintEmployee(emp))
}
// employee.go
package main

type Employee struct {
    name string
    age  int
}

func NewEmployee() *Employee {
    return &Employee{name: "Sam", age: 25}
}

func PrintEmployee(p *Employee) string {
    return p.name
}

Step-by-step

  1. Go loads the current package.
  2. It sees both main.go and employee.go because both are in the same folder and package.
  3. main() starts running.
  4. NewEmployee() is called.
  5. NewEmployee() creates an Employee value and returns a pointer to it.
  6. That pointer is stored in emp.
  7. PrintEmployee(emp) is called.
  8. PrintEmployee accesses p.name and returns it.
  9. fmt.Println(...) prints the name.

What happens if you run only one file?

If you run:

go run main.go

then Go compiles only main.go.

At that point:

  1. Go reads main.go
  2. It finds NewEmployee()
  3. It cannot find a definition in that file
  4. It reports:
undefined: NewEmployee

That is why building the whole package matters.

Real World Use Cases

This concept is used constantly in real Go projects.

Splitting code by responsibility

A package may be divided into multiple files such as:

  • main.go for program startup
  • employee.go for employee-related types and functions
  • db.go for database access
  • config.go for configuration loading

All of these can belong to the same package if they are closely related.

Keeping code readable

As a program grows, putting everything in one file becomes hard to manage. Multiple files let you:

  • group related types and functions
  • reduce clutter
  • make code easier to navigate

Building command-line tools

In a CLI app, you might have:

  • main.go to parse flags
  • commands.go to define command handlers
  • helpers.go for utility functions

They can all work together in the same package.

Web applications

A small web server might use:

  • main.go for startup
  • routes.go for route setup
  • handlers.go for HTTP handlers
  • models.go for data structures

Again, package-level visibility allows direct access across files.

Take Quiz

Real Codebase Usage

In real projects, developers use package-level organization intentionally.

Common patterns

Grouping related code in one package

A package often contains several files:

  • user.go
  • user_service.go
  • user_validation.go

All can share unexported helpers if they are in the same package.

Constructors

Functions like NewEmployee() are common constructor-style functions:

func NewEmployee(name string, age int) *Employee {
    return &Employee{name: name, age: age}
}

This helps centralize setup logic.

Validation before creation

func NewEmployee(name string, age int) (*Employee, error) {
    if name == "" {
        return nil, errors.New("name is required")
    }
    if age < 0 {
        return nil, errors.New("age cannot be negative")
    }
    return &Employee{name: name, age: age}, nil
}

This is common in production code.

Unexported helpers

A package may hide internal logic in lowercase functions:

func normalizeName(name string) string {
    return strings.TrimSpace(name)
}

These helpers are visible across files in the same package, but not outside it.

Early returns and guard clauses

Go code often uses simple early exits:

func PrintEmployee(p *Employee) string {
    if p == nil {
        return "no employee"
    }
    return p.name
}

This keeps logic readable and safe.

Common Mistakes

Here are common mistakes beginners make with this topic.

1. Running only one file

Broken

go run main.go

If NewEmployee() is in another file, this can cause:

undefined: NewEmployee

Fix

go run .

or:

go build

2. Using different package names in the same folder

Broken

// main.go
package main
// employee.go
package employee

Files in one folder generally need to belong to the same package for this kind of direct access.

Fix

Use the same package name if they are meant to compile together:

package main

3. Forgetting to export names across packages

If files are moved into different packages, lowercase names are not accessible.

Broken

package employee

func newEmployee() *Employee {
    return &Employee{}
}
package main

import "myapp/employee"

func main() {
    employee.newEmployee()
}

Fix

Use an uppercase first letter:

func NewEmployee() *Employee {
    return &Employee{}
}

4. Incorrect function signature

Your original PrintEmployee returned a string but did not declare it correctly.

Broken

func PrintEmployee(p *Employee) {
    return "Hello world!"
}

Fix

func PrintEmployee(p *Employee) string {
    return "Hello world!"
}

5. Declaring a variable and not using it

In Go, unused local variables cause compile errors.

Broken

func main() {
    emp := NewEmployee()
}

Fix

Use it:

func main() {
    emp := NewEmployee()
    _ = emp
}

or print it.

6. Putting files in different directories without imports

If files are in different folders, they are usually different packages. You cannot call functions directly without importing the package.

Comparisons

SituationCan you call the function directly?What is required?
Same package, same folder, built togetherYesSame package name
Same package, but only one file is runNoRun/build the whole package
Different packagesNoImport the package and use exported names
Same folder, different package namesNoReorganize package structure

Same package vs different package

FeatureSame packageDifferent package
Direct access to functionsYesNo
Need importNoYes
Can use lowercase namesYesNo
Can use uppercase namesYesYes, if exported

go run main.go vs go run .

CommandWhat it does
go run main.goRuns only main.go
go run .Runs all Go files in the current package

For multi-file programs in one package, go run . is usually the correct choice.

Take Quiz

Cheat Sheet

// File 1
package main

func Hello() string {
    return "hi"
}
// File 2
package main

func main() {
    println(Hello())
}

Rules

  • Files in the same package can use each other's functions directly.
  • Files must usually be in the same directory and use the same package name.
  • Run the whole package with:
    • go run .
    • go build
  • If you run only one file, other files are not included.
  • Uppercase names are exported.
  • Lowercase names are package-private.
  • Across different packages, you must:
    • import the package
    • use exported names only

Common fix for undefined

If your code is split across files in one package:

go run .

Correct function return syntax

func PrintEmployee(p *Employee) string {
    return "Hello world!"
}

Constructor-style function

func NewEmployee() *Employee {
    return &Employee{}
}

FAQ

Why does Go say a function is undefined when it is in another file?

Usually because you ran only one file, such as go run main.go, instead of building the whole package.

How do I run all Go files in the same package?

Use:

go run .

Do files in the same Go package need imports between them?

No. Functions, types, and variables in the same package are available directly.

Does the function name need to start with an uppercase letter?

Only if you want to use it from another package. Inside the same package, lowercase names also work.

Can two files in the same folder have different package names?

Not for normal package usage like this. If they do, they are treated as different packages and cannot access each other directly.

Why does my PrintEmployee function fail to compile?

Because it returns a string but the function signature did not declare a return type.

What is the difference between go build and go run .?

go build compiles the package. go run . compiles and runs it immediately.

Can I split a Go package into many files?

Yes. That is a common and recommended way to organize related code.

Take Quiz

Mini Project

Description

Create a small multi-file Go program that manages employees. This project demonstrates how functions, structs, and constructor-style functions work across multiple files in the same package.

Goal

Build and run a two-file Go program where main.go creates an employee using a function from employee.go and prints employee information.

Requirements

Requirement 1 Requirement 2 Requirement 3

Take Quiz

Keep learning

Related questions

View more