Last Updated: May 22, 2026
You have Go installed. Now it's time to write code, run it, and see output on your screen. This lesson walks through the anatomy of a Go source file, explains each piece that makes a program work, and covers the commands you need to run your code.
Every programming journey starts somewhere. In Go, the smallest possible program that prints to the screen looks like this:
Save this in a file called main.go, open a terminal in that folder, and run:
That single command compiles and executes the file. You should see Hello, World! printed to your terminal. If you do, your Go installation is working and you just ran your first Go program.
There are only four lines of actual code here, but each one matters. The rest of this lesson breaks them down one at a time.
Every Go source file follows the same structure, in the same order. There's no flexibility here, and that's intentional. Go enforces a consistent layout so every file in every Go project looks familiar.
The order is always: package declaration first, then imports, then everything else. The Go compiler rejects files that break this order. This rigid structure means you never have to guess where to find the package name or imports in any Go file, whether it's your own code or someone else's.
The very first line of every Go file is the package declaration. It tells Go which package this file belongs to.
Go organizes code into packages. Every file must declare which package it's part of, and every file in the same folder must use the same package name. If you have three .go files in a directory, they all need to say package main (or whatever the package name is).
The name main is special. It tells the Go compiler "this package is an executable program, not a library." When Go sees package main, it knows to produce a binary you can run. Any other package name (like package orders or package inventory) creates a library that other code can import but can't run on its own.
This distinction is fundamental. A Go project might have dozens of packages, but only one of them is package main with a main() function. That's the one the user actually runs.
After the package declaration comes the import block. This is where you tell Go which packages your code uses.
The fmt package (short for "format") is part of Go's standard library. It provides functions for formatted printing and reading input. fmt.Println is the one you'll use most often early on, as it prints a line of text followed by a newline.
When you need multiple packages, you have two options. You can write separate import statements:
Or you can group them into a single block with parentheses, which is what most Go developers do:
Both forms work identically. The grouped form is more common because it's easier to read when you have several imports. Go's formatting tool gofmt will organize them for you, so don't worry about ordering.
One important rule: Go does not allow unused imports. If you import a package and don't use it anywhere in the file, the compiler refuses to build your code. This isn't a warning you can ignore. It's a hard error.
Trying to compile this gives:
This keeps codebases clean. Dead imports slow down compilation and confuse readers who wonder why a package is there.
The func main() function is where your program starts running. When you execute a Go program, the runtime calls main() in package main. That's the entry point, and there can be only one.
A few things to note about main():
os.Args slice, not function parameters.os.Exit().main() function per program, inside package main.The curly brace placement matters too. Go requires the opening brace { on the same line as the function declaration. This won't compile:
The compiler produces an error because Go's automatic semicolon insertion adds a semicolon after main(), which breaks the syntax. Most languages let you choose where to place braces. Go doesn't. The opening brace goes on the same line, always.
fmt.Println prints its arguments to the terminal, separated by spaces, followed by a newline. It's the simplest way to see output from your program.
Notice that fmt.Println accepts multiple arguments of different types. You can pass strings, numbers, and other values, and it figures out how to display them. Each Println call adds a newline at the end, so each call starts output on a new line.
For more control over formatting, there's fmt.Printf, which uses format verbs like %s for strings and %d for integers:
Printf doesn't add a newline automatically, so you include \n yourself. The %.2f format verb prints a floating-point number with exactly two decimal places, which is useful for prices.
You've already seen go run, which compiles and immediately executes your code. There's also go build, which compiles your code into a binary file you can run later.
Here's the difference:
| Command | What It Does | Produces a File? |
|---|---|---|
go run main.go | Compiles and runs immediately | No (temporary binary, deleted after) |
go build | Compiles into an executable binary | Yes (stays on disk) |
For day-to-day development, go run is faster because you skip the step of finding and running the binary. For deploying to a server or sharing with someone, go build creates a standalone executable.
The -o shop flag names the output binary shop. Without it, Go uses the module name or directory name. The resulting file is a self-contained executable with no dependencies. You can copy it to another machine with the same operating system and architecture, and it runs without installing Go.
Before writing anything beyond a single file, you need a Go module. A module is Go's unit of dependency management. It tracks which packages your project uses and their versions.
Create a new directory for your project, then initialize a module:
This creates a go.mod file that looks like:
The module name (myshop here) identifies your project. For code you plan to share publicly, convention is to use a URL-like path such as github.com/yourname/myshop. For learning and local projects, a simple name works fine.
After running go mod init, create a main.go file in that directory and you're ready to write code. The go run . command (note the dot) compiles and runs all .go files in the current directory that belong to package main.
Here's a complete example. After running go mod init myshop, create this main.go:
Now that you understand each piece, here's a program that uses everything covered so far. It prints an order confirmation with product details and a total.
This program doesn't do anything fancy. No variables for the items, no loops, no calculations beyond adding three numbers. Those tools come in later sections. The point here is to see the structure: package main, an import, func main(), and fmt functions doing the output work.
Go's compiler is strict. It catches errors that other languages treat as warnings or ignore entirely. Here are the mistakes you're most likely to hit in your first few programs.
What's wrong with this code?
Every Go file must start with a package declaration. Without it, the compiler produces:
Fix: Add package main as the very first line.
What's wrong with this code?
The math package is imported but never used. Go's compiler error:
Fix: Remove the import "math" line, or use something from the math package.
Go also rejects unused local variables. This one surprises many beginners.
What's wrong with this code?
The variable discount is declared but never used:
Fix: Either use the variable or remove it. If you're temporarily not using it during development, you can assign it to the blank identifier:
The blank identifier _ tells Go "I know this exists, and I'm intentionally not using it." This is a temporary workaround for development, not something you'd leave in finished code.
What's wrong with this code?
Go requires the opening { on the same line as the function signature. Placing it on the next line causes:
Fix: Move the opening brace to the end of the func main() line.
When you type go run main.go, several steps happen in sequence. Understanding the basic flow helps when something goes wrong.
func main().With go run, the binary is created in a temporary directory and deleted after the program finishes. With go build, the binary stays on disk for you to run whenever you want.
The key takeaway is that Go is a compiled language. There's no interpreter running your code line by line. The compiler catches many bugs before your program ever executes, which is why the strict rules around unused imports and variables exist. They're compile-time checks, not runtime checks.