🚧 We are still building the lighthouse. Hang tight!

projectlighthouse logoprojectlighthouse

Sign in with your Google or GitHub account to get started

Getting Started with Go

Understand why Go exists, what problems it solves, and how to install and run your first Go program. Learn about Go's philosophy, compilation speed, static binaries, and the standard library.

Go, a programming language built to tackle the complexity of modern day software engineering. Software that grows, that runs on servers, handles thousands of simultaneous connections, and deploys as a single binary. It compiles in seconds, includes a production-ready standard library, and makes concurrent programming straightforward rather than terrifying.

The language emerged from Google in 2009, designed by Robert Griesemer, Rob Pike, and Ken Thompson. Thompson co-created Unix and C. Pike worked on Plan 9 and UTF-8. They weren't academic researchers exploring type theory—they were engineers tired of waiting for builds to finish and debugging thread synchronization issues.

What Go Gives You

In software engineering, everything has a tradeoff. It is the same for Go. These are some of the key features Go gives us. Consider them the “pros”.

Simplicity, I’ll start off with simplicity. The Go team took this as a pillar for their design. And as software grows, it is very difficult to keep things simple. Which becomes a feature of it’s own when you are building large scale software. The entire language specification is readable in an afternoon. There aren't many features, but the features that exist compose cleanly. You can become productive in Go quickly.

Being a statically typed compiled language, meaing completes a set of tasks during that time, for example; enforcing strict static typing, verifies interface satisfaction, ensuring proper conversion assertions, detecting unused variables, import cycles and many other alike! Each of them important, yet Go has fast compilation large codebases compile in seconds. The entire standard library builds in under a minute. You change code, hit save, and immediately see if it works. This tight feedback loop changes how you develop.

Static binaries, Go programs compile to single executables with no external dependencies. The binary includes your code, the Go runtime (garbage collector, scheduler), and all libraries. You can literally copy it to a server and run it—no interpreters, no virtual machines, no "works on my machine" debugging.

In the 21st century, most of the language are still in a way that they are build for single core machines! But modern computers can and does come with many cores. Not just one. Yet, the languages still behave the old way. The Go team, built Go with this in mind, that it should be able to run on single core machines, but also when there are more cores available, Go should be able to utilise that.

One of the best decisions is that the team didn’t go for parallelism (only) but concurrency. Go has built-in concurrency. In go, you can design your code in a way, when you 1 core or 10, you can utilise the same code, without code change or overhead! Btw, Rob Pike has an amazing lecture on this Concurrency is not Parallelism by Rob Pike .

Go programs can spawn thousands of lightweight threads (goroutines) that run concurrently. Channels let goroutines communicate safely without shared memory and locks. Writing concurrent code feels natural, not like defusing a bomb. We’ll discuss about goroutines in more depth in the upcoming chapters.

Now, another part that is quite crucial is memory management of your program. This has always been um… a challenge to say the least. The linux kernel, written in C has memory bugs that has been there for years or maybe even decades! C, gives you full control. You, the programmer is responsible for allocating and freeing up memory. With Go, you get a built in garbage collector, that takes away the heavy-lifting. This helps new developers to build up fast, enables faster delivery time and no manual reference counting, your program’s memory footprint remains small.

Go’s garbage collector is not the silver bullet, not the solution to everything, there is always a tradeoff.

What else… yah, libraries. Go has a comprehensive standard library, HTTP servers, JSON encoding, cryptography, testing, file I/O—it's all included. You build APIs and services without installing frameworks. Most if not all of them exposed via interfaces, in case you need to implement your own thing. We’ll also learn about Go’s interfaces in a later chapter. Go also comes with an amazing ecosystem of packages (libraries). We can find everything in the standard library, but the community’s got our back.

Need to connect to kafka? We have segmentio/kafka-go: Kafka library in Go , securing your API with JWT can be handled with golang-jwt/jwt: Go implementation of JSON Web Tokens (JWT) , to mock during your tests you can utilise uber-go/mock: GoMock is a mocking framework, need to process some packets ? Google has a fancy tool google/gopacket: Provides packet processing capabilities for Go, gorilla has a nice suit of toolkit, Gorilla, the golang web toolkit … you get the idea. And if you are still missing something, build and share :)

Go has widely been adopted by many tech companies, many CNCF (Cloud Native Computing Foundation) projects are built using Go as well. Companies like google, digitalocean, dropbox, discord, docker uses Go.

Getting Started: Installation

Now, lets get started with Go. Go's toolchain is a single download. Visit golang.org/dl (simple right?), grab the installer for your operating system, and run it. The entire toolchain—compiler, test runner, formatter, module manager—is one command: go.

Verify it works:

go version
# go version go1.23.1 darwin/arm64

# your version will likely be different

That's it. No package managers to configure, no environment variables to set (beyond adding Go to your PATH, which the installer usually handles), no dependency conflicts to resolve.

Hello World

I started my programming journey in the early 2010s. I started with a Hello, World program in C, just like many other programmers in the world. Lets do the same for Go. Create a file called main.go:

package main

import "fmt"

func main() {
    fmt.Println("Hello, World!")
}

Run it:

go run main.go
# Hello, World!

Three things are happening here. The package main line declares this file is part of the main package—the special package that produces executable programs. The import "fmt" line brings in the formatted I/O package from the standard library. The func main() function is where execution starts.

Go requires explicit imports. You can't use fmt.Println without importing fmt, and unused imports cause compilation errors. This keeps code clean—no dead imports accumulating over time.

Building Executables

go run compiles and executes in one step, useful for quick tests. To create a standalone binary, use go build:

go build main.go
./main
# Hello, World!

Check what you just created:

ls -lh main
# -rwxr-xr-x  1 user  staff   1.8M Oct 26 10:30 main

file main
# main: Mach-O 64-bit executable arm64

The binary is 1.8MB for a hello world program. That's large compared to a C program that prints text, but the Go binary includes the garbage collector, goroutine scheduler, and panic handler. Everything needed to run is self-contained. And this is also unoptimised binary.

This binary runs on any machine with the same operating system and CPU architecture. No Go installation required on the target machine. Just copy and execute. Go also has cross compilation support, something we’ll discuss in a future chapter.

Package Organization

Go code organizes into packages. A package is a directory containing .go files that all declare the same package name. Here's a typical project:

myproject/
  main.go          (package main)
  server/
    http.go        (package server)
    routes.go      (package server)
  database/
    postgres.go    (package database)

The main package must have a func main() that takes no parameters and returns nothing. When you run the program, execution starts there.

Other packages are libraries. They export functions, types, and variables that other packages import. Visibility is determined by capitalization: capitalized identifiers are exported (public), lowercase identifiers stay within the package (private).

package server

// Start is exported - visible to other packages
func Start() {
    initialize()
}

// initialize is private - only package server sees it
func initialize() {
    // ...
}

No keywords like public, private, or protected. Just look at the first letter and you know the scope. This simplicity extends throughout the language—fewer concepts to learn means faster understanding. Again, something for a later chapter.

The Standard Library

Go's standard library handles tasks that require external frameworks in other languages. Here's a complete JSON API server:

package main

import (
    "encoding/json"
    "net/http"
)

func handler(w http.ResponseWriter, r *http.Request) {
    data := map[string]string{"message": "Hello, World!"}
    json.NewEncoder(w).Encode(data)
}

func main() {
    http.HandleFunc("/", handler)
    http.ListenAndServe(":8080", nil)
}

Run it and test:

go run main.go &
curl http://localhost:8080
# {"message":"Hello, World!"}

No dependencies beyond the standard library. The HTTP server handles production traffic—it's not a toy. Companies serve billions of requests using Go's net/http package.

Go 1's compatibility promise means code written in 2012 still compiles today. The standard library doesn't break backward compatibility. You upgrade Go versions without rewriting code or dealing with deprecation warnings.

What Go Leaves Out

Go deliberately omits features found in other languages. These aren't oversights—they're conscious decisions to keep the language small.

No inheritance. Go uses composition through struct embedding instead of class hierarchies. This eliminates fragile base class problems and deep inheritance trees.

No operator overloading. The + operator adds numbers and concatenates strings. That's it. You can't redefine it. Reading code reveals exactly what operations do.

No implicit type conversions. Converting between numeric types requires explicit conversion. This prevents subtle bugs from silent conversions.

No exceptions. Functions that can fail return error values that you check explicitly. Error handling is visible in the control flow.

These omissions keep Go learnable. The language specification is short enough to read in an afternoon. Teams become productive quickly because there's less to learn.

Where Go Shines

Go excels at building networked services, command-line tools, and distributed systems. The standard library includes everything needed for HTTP servers and clients. Concurrency primitives handle thousands of simultaneous connections efficiently. Static binaries deploy easily.

Real-world Go usage:

  • APIs and microservices (Docker, Kubernetes)
  • Command-line tools (Terraform, Hugo)
  • Network servers and proxies
  • Data processing pipelines
  • Distributed systems infrastructure

Go isn't ideal for everything. GUI applications are awkward—there's no native widget toolkit. Heavy numerical computing favors languages with mature libraries like NumPy or specialized tools like Julia. Quick scripts often work better in Python or Bash unless you need Go's performance.

The language targets backend infrastructure and developer tools. If you're building services, APIs, or command-line applications, Go's strengths align well.

What's Next

You've got Go installed and understand how it compiles and runs. Now you'll learn the language itself—how data works, how programs make decisions, how memory organizes, and how concurrency enables parallelism.

Go's simplicity is strategic. Fewer features mean fewer ways to accomplish tasks, which means more consistent codebases. The following articles build progressively: we'll start with values and types (how data works), move through control flow (how programs make decisions), explore collections and memory layout, then progress to functions, methods, error handling, and finally concurrency.

Each concept builds on what came before. Go optimizes for reading and maintaining code, not for clever one-liners or exotic features. This philosophy becomes clear as you write more Go—the language nudges you toward solutions that you'll understand six months later.

Next

Values, Variables, and Constants

Notes & Highlights

© 2025 projectlighthouse. All rights reserved.