Go Hello World — Package main func main and go run Explained
In this tutorial, you will learn about Go Hello World. We cover key concepts, practical examples, and best practices to help you master this topic.
Go's hello world demonstrates package main for executable programs, func main as the entry point, the fmt package for formatted I/O, and go run for compiling and executing in one step.
What You'll Learn
- The structure of a Go program
- Package main and func main
- The fmt package for output
- Building and running Go programs
Why It Matters
Every Go program follows the same structure. Understanding package main and func main is the foundation for all Go development. Docker, Kubernetes, and every Go application starts with this same pattern.
Real-World Use
Command-line tools, web servers, API services — every executable Go program begins with package main and func main. This is the entry point that the Go runtime calls when executing your program.
flowchart LR
A["Hello World"] --> B["Package main"]
B --> C["func main"]
C --> D["fmt.Println"]
D --> E["go run"]
A:::current --> B
style A fill:#2563eb,stroke:#2563eb,color:#fff
style B fill:#dbeafe,stroke:#2563eb,color:#1e40af
style C fill:#dbeafe,stroke:#2563eb,color:#1e40af
style D fill:#dbeafe,stroke:#2563eb,color:#1e40af
style E fill:#f1f5f9,stroke:#94a3b8,color:#64748b
Your First Go Program
Create hello.go:
package main
import "fmt"
func main() {
fmt.Println("Hello, World!")
fmt.Println("Welcome to Go programming")
}
Run it:
go run hello.go
Output:
Hello, World!
Welcome to Go programming
Breaking Down the Program
Package Declaration
package main
Every Go file belongs to a package. package main tells Go to compile this as an executable. Other package names (like package utils) create reusable libraries.
Import Statement
import "fmt"
Imports are explicitly declared. Go's standard library provides packages like fmt (formatting), os (operating system), net/http (HTTP), and many more.
Func Main
func main() {
// ...
}
func main() is the entry point. Execution starts here. It takes no arguments and returns nothing. For command-line arguments, use os.Args.
The fmt Package
package main
import "fmt"
func main() {
fmt.Print("No newline")
fmt.Println("With newline")
fmt.Printf("Formatted: %s is %d years old\n", "Alice", 25)
name := "Bob"
age := 30
message := fmt.Sprintf("Stored: %s (%d)", name, age)
fmt.Println(message)
}
Output:
No newlineWith newline
Formatted: Alice is 25 years old
Stored: Bob (30)
Compilation vs Interpretation
# Run without building (compile + execute in temp dir)
go run hello.go
# Build to binary
go build hello.go
./hello
# Install binary to GOPATH/bin
go install hello.go
# Build with custom name
go build -o myapp hello.go
Build Output
go build -o hello hello.go
ls -lh hello
# -rwxr-xr-x 1 user user 1.8M Jun 28 10:00 hello
file hello
# hello: ELF 64-bit LSB executable, x86-64
Multiple Files
As programs grow, split them into multiple files in the same package:
// main.go
package main
func main() {
greet("Alice")
}
// greet.go
package main
import "fmt"
func greet(name string) {
fmt.Println("Hello,", name)
}
go run main.go greet.go
# Hello, Alice
Cross-Compilation
Build for different platforms:
# Build for Windows
GOOS=windows GOARCH=amd64 go build -o hello.exe hello.go
# Build for macOS
GOOS=darwin GOARCH=amd64 go build -o hello-mac hello.go
# Build for ARM Linux
GOOS=linux GOARCH=arm64 go build -o hello-arm hello.go
Adding Comments
package main // Package declaration
import "fmt" // Standard library for formatting
func main() {
// This is a single-line comment
fmt.Println("Hello") // Inline comment
/*
This is a
multi-line comment
*/
fmt.Println("World")
}
Common Mistakes
1. Wrong Package Name for Executables
// Wrong — package must be main
package myapp
// Right
package main
2. Unused Imports
// Wrong — won't compile
import (
"fmt"
"strings" // Unused import!
)
// Right — remove unused imports
import "fmt"
3. Missing main Function
package main
// No func main — won't produce executable
4. Wrong Brace Placement
Go requires the opening brace on the same line:
// Wrong
func main()
{
}
// Right
func main() {
}
5. Using fmt.Println vs fmt.Printf Incorrectly
// Wrong — Println doesn't format
fmt.Println("Name: %s", name) // Prints literal "%s"
// Right — use Printf for formatting
fmt.Printf("Name: %s\n", name)
Practice Questions
1. Why must executable Go programs use package main?
package main is a special package name that tells the Go compiler to produce an executable binary. Other package names produce libraries that can be imported but not run directly.
2. What's the difference between go run and go build?
go run compiles and runs the program without leaving a binary. go build compiles and creates an executable file that can be distributed and run without the Go toolchain.
3. How do you print formatted output in Go?
Use fmt.Printf with format verbs like %s (string), %d (integer), %f (float), %v (default format), and \n for newline.
4. What happens if you import a package but don't use it?
Go won't compile. You must use every imported package, or remove unused imports. The goimports tool can manage imports automatically.
Challenge: Create a Go program that accepts command-line arguments and prints a personalized greeting.
Solution
package main
import (
"fmt"
"os"
)
func main() {
args := os.Args
if len(args) < 2 {
fmt.Println("Usage: go run main.go <name>")
return
}
name := args[1]
fmt.Printf("Hello, %s! Welcome to Go programming.\n", name)
fmt.Printf("You provided %d arguments.\n", len(args)-1)
}
go run main.go Alice
# Hello, Alice! Welcome to Go programming.
# You provided 1 arguments.
FAQ
{{< faq question="Can I have multiple main functions in the same package?" >}} No. Each package can have at most one main function. Multiple files in the same package share the same scope — duplicate main functions would conflict. {{< /faq >}}
{{< faq question="What's the difference between fmt.Print and fmt.Println?" >}}
fmt.Print prints without a trailing newline. fmt.Println adds a newline after printing. fmt.Printf supports format verbs and also doesn't add a newline.
{{< /faq >}}
{{< faq question="How big is a Hello World binary?" >}}
About 1.5-2 MB. Go includes its runtime (garbage collector, Goroutine scheduler) in every binary, which accounts for most of the size. Use -ldflags="-s -w" to strip debug info and reduce size.
{{< /faq >}}
{{< faq question="Do I need to compile Go programs before running them?" >}}
go run compiles automatically. For distribution, use go build to create a standalone binary. Go programs don't need a runtime or VM to run.
{{< /faq >}}
{{< faq question="Can I run a single .go file without a module?" >}}
Yes, for simple programs. But Go modules are recommended and required for projects with dependencies. Use go mod init to create a module.
{{< /faq >}}
Try It Yourself
package main
import (
"fmt"
"runtime"
"time"
)
func main() {
fmt.Println("=== Go Program Info ===")
fmt.Printf("File: %s\n", "hello.go")
fmt.Printf("Time: %s\n", time.Now().Format(time.RFC1123))
fmt.Printf("Go Version: %s\n", runtime.Version())
fmt.Printf("OS/Arch: %s/%s\n", runtime.GOOS, runtime.GOARCH)
fmt.Println("======================")
}
Expected output:
=== Go Program Info ===
File: hello.go
Time: Sun, 28 Jun 2026 10:00:00 UTC
Go Version: go1.24.0
OS/Arch: linux/amd64
======================
What's Next
Now that you can write and run Go programs, learn about variables and data types.
| Topic | Description | Link |
|---|---|---|
| Go Variables | var, :=, types, zero values, constants | {{< ref "04-variables" >}} |
| Go Control Flow | if/else, for, switch, defer | {{< ref "05-control-flow" >}} |
| Rust Variables | Compare Rust variable handling | Rust |