LearnAI ToolsCareerPractice BuildsPlayContact
Lesson 4221 min read

Best Practices & Deployment

Learn idiomatic Go style with gofmt and effective naming, how to build production binaries with go build, cross-compilation with GOOS/GOARCH, and a brief look at Docker deployment.

Introduction

You have now covered the language itself, concurrency, I/O, JSON, web servers, testing, and generics. This final lesson closes the loop: how to write Go that looks like Go, how to compile it into a real deployable binary, how to target other operating systems and architectures from a single machine, and how that binary typically ends up running in production.

What You Will Learn
  • How gofmt enforces a single, consistent Go style automatically.
  • Idiomatic naming conventions used throughout the Go ecosystem.
  • How to build an optimized, production-ready binary with go build.
  • How to cross-compile for a different OS/architecture using GOOS and GOARCH.
  • How a Go binary typically fits into a minimal Docker deployment.

Idiomatic Style with gofmt

Go ships with an opinionated formatter, gofmt, that rewrites your source code into the one true Go style — consistent indentation, spacing, and alignment. There is deliberately no configuration; every Go codebase in the world is formatted the same way, which eliminates an entire category of style debates.

gofmt -l . # list files that are not formatted correctly
gofmt -w . # rewrite files in place
go vet ./... # catch suspicious constructs gofmt cannot
Editor Integration

Most Go editors and IDEs run gofmt automatically on save. Combined with go vet (which flags suspicious code like format-string mismatches), this should be part of every developer's default workflow.

Effective Naming

Go favors short, clear names over long, descriptive ones — especially for local variables with a small scope. Package names are short, lowercase, and singular; exported identifiers use MixedCaps rather than underscores.

ConventionExampleNotes
Package nameshttp, json, mathutilShort, lowercase, no underscores.
Exported identifiersReadFile, HTTPClientMixedCaps, capitalized first letter.
Unexported identifiersreadBuffer, isValidMixedCaps, lowercase first letter.
Short-lived local variablesi, err, w, rShort names are idiomatic in small scopes.
AcronymsID, URL, HTTP (not Id, Url, Http)Keep acronyms fully capitalized.

Building Production Binaries

go build compiles your program into a single, statically linked executable with no external runtime dependency — no interpreter, no JVM, nothing else to install on the target machine. For production, it is common to strip debug information to shrink the binary and pass build-time variables like a version string.

go build -o myapp .
# a leaner production build: strip symbols, inject a version string
go build -ldflags="-s -w -X main.version=1.4.0" -o myapp .
Output

Click Run to see what this code prints.

That single myapp file is everything you need to run the program — copy it to a server, or into a container, and execute it directly.

Cross-Compilation with GOOS/GOARCH

One of Go's standout deployment features is built-in cross-compilation: you can build a binary for Linux, Windows, or macOS, on any architecture, directly from your development machine, just by setting two environment variables before go build.

GOOS=linux GOARCH=amd64 go build -o myapp-linux-amd64 .
GOOS=windows GOARCH=amd64 go build -o myapp-windows-amd64.exe .
GOOS=darwin GOARCH=arm64 go build -o myapp-macos-arm64 .
GOOSGOARCHTarget
linuxamd64Standard 64-bit Linux servers
linuxarm64ARM-based Linux servers/containers (e.g. AWS Graviton)
windowsamd6464-bit Windows
darwinarm64Apple Silicon Macs

This means a CI pipeline running on a single Linux build agent can still produce ready-to-run binaries for every platform your users need, with no separate build machines required.

A Brief Note on Docker Deployment

Because a Go binary is statically linked and self-contained, it pairs naturally with a minimal, multi-stage Docker build: compile in a full Go image, then copy just the resulting binary into a tiny final image with no Go toolchain at all.

Dockerfile
FROM golang:1.22 AS builder
WORKDIR /app
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -o myapp .
FROM scratch
COPY --from=builder /app/myapp /myapp
ENTRYPOINT ["/myapp"]

The final image built from scratch contains nothing but your compiled binary — often just a few megabytes — which keeps deployment images small, fast to pull, and with a minimal attack surface.

Common Mistakes

Avoid These Mistakes
  • Committing unformatted code instead of running gofmt (or letting your editor do it) before every commit.
  • Using verbose, Java-style getter/setter naming instead of idiomatic short Go names.
  • Forgetting CGO_ENABLED=0 when building for a minimal base image like scratch or alpine, causing a dynamically linked binary that fails to run.
  • Shipping debug symbols and unstripped binaries to production, bloating the deployed artifact.
  • Ignoring go vet warnings, missing real bugs it was specifically designed to catch.

Best Practices

  • Run gofmt and go vet as part of your standard workflow, ideally enforced in CI.
  • Follow Go naming conventions: short local names, MixedCaps for exported identifiers, capitalized acronyms.
  • Build with -ldflags="-s -w" for production to strip debug information and reduce binary size.
  • Use multi-stage Docker builds so your final image contains only the compiled binary, not the whole toolchain.
  • Set CGO_ENABLED=0 for fully static binaries when targeting minimal container base images.

Frequently Asked Questions

No. go build produces a statically linked, self-contained binary that runs directly on the target OS/architecture with no separate Go installation required.

CGO_ENABLED controls whether cgo (linking against C libraries, such as for certain DNS or SQLite drivers) is used. Setting it to 0 forces a fully static binary, which is required for minimal images like scratch that have no C runtime at all.

Yes. Set GOOS=windows GOARCH=amd64 before go build, and the Go toolchain cross-compiles the executable without needing a Windows machine at all.

Key Takeaways

  • gofmt enforces one consistent style across every Go codebase, with no configuration needed.
  • Go naming favors short, clear identifiers and MixedCaps over underscores.
  • go build produces a single, statically linked, dependency-free production binary.
  • GOOS and GOARCH enable cross-compilation for any target platform from any development machine.
  • Multi-stage Docker builds combine well with Go binaries to produce small, minimal deployment images.

Summary

Idiomatic style, a simple build toolchain, effortless cross-compilation, and a natural fit for minimal container images are a big part of why Go has become a default choice for backend services and command-line tools alike. With this lesson, you have gone from Go fundamentals all the way through concurrency, real-world I/O, and production deployment.

Go Course Completed!

You have successfully completed all 42 lessons — from Go fundamentals and structs/interfaces through goroutines, channels, and building real concurrent web services. You now have a genuinely practical, production-ready Go skill set.

Browse All Courses →