The missing manual
You just finished a utility package for parsing configuration files. You push it to your team repository. The next morning, a teammate sends you a message asking how to initialize the parser. You do not have a README. You do not have a wiki. You have Go. The language already ships with a documentation engine. It lives in your terminal, reads your source code, and formats it on demand. You just need to write the comments in the exact format the toolchain expects.
Go treats documentation as a first-class citizen of the build system. Other languages require separate generators like Sphinx, JSDoc, or Doxygen. Go uses the same parser that compiles your code. When you run go doc, the toolchain scans your source files, builds an abstract syntax tree, extracts comments that follow specific formatting rules, and prints them to standard output. The system is strict by design. A comment that does not match the expected pattern is ignored. This keeps the output clean and forces developers to write documentation that matches the public API.
Capitalization controls visibility. Exported names start with a capital letter. Unexported names start lowercase. The documentation tool only shows exported symbols. If you document a lowercase function, the comment is treated as internal notes. The toolchain will not surface it. This convention ties your documentation directly to your API surface.
Documentation in Go is not a separate step. It is part of the code.
How Go reads your comments
The go doc command does not guess. It follows a rigid set of rules that mirror how the compiler resolves symbols. Every package needs a package-level comment. Every exported type, function, method, and constant needs a declaration comment. The comment must sit immediately above the declaration with no blank lines between them. If you insert a blank line, the comment becomes a regular code comment. The documentation parser skips it.
The first sentence of a doc comment must be a complete sentence that starts with the name of the declared item. This rule exists so the toolchain can extract a one-line summary for index pages and search results. The rest of the comment can contain paragraphs, code examples, and cross-references. The parser treats consecutive lines as a single paragraph. Blank lines inside the comment create new paragraphs.
Here is the simplest valid package structure:
// Package config provides utilities for loading and validating YAML settings.
package config
// Load reads a YAML file and returns a parsed configuration object.
// It returns an error if the file is missing or contains invalid syntax.
func Load(path string) (*Settings, error) {
// open the file for reading
// parse the YAML content into a map
// validate required fields
// return the populated settings struct
}
The compiler reads your comments. Write them like code.
Under the hood: parsing and presentation
When you run go doc ./config, the toolchain invokes the same go/parser package that handles compilation. It walks the AST and collects nodes marked as exported. It attaches the preceding comment group to each node. The formatter then strips leading whitespace, aligns paragraphs, and prints the result. Unexported symbols are filtered out before rendering. This is why go doc never shows internal helpers. The documentation surface matches the importable surface.
The toolchain also handles cross-package references automatically. If you mention http.Server in a comment, go doc knows it is a standard library type. It will format it correctly and link to it in HTML output. You do not need to manually escape names or add markdown links. The parser resolves them against the import graph.
Package-level comments are special. They must appear in a file named doc.go or at the top of any file in the package. If multiple files contain package comments, the toolchain merges them. This allows large packages to split documentation across files without losing context. The merged comment appears first when you run go doc on the package path.
The parser ignores comments that do not follow the naming rule. If your function comment starts with Reads a file... instead of Load reads a file..., the summary extraction fails. The full comment still prints, but index tools and search engines will treat it as unstructured text. Stick to the naming convention. It saves you from broken documentation indexes later.
Format matters. The toolchain ignores anything that breaks the pattern.
Realistic package documentation
Production packages need more than function signatures. They need type documentation, method documentation, and executable examples. Go supports example functions that double as documentation and tests. The naming convention is strict. An example for a package starts with Example. An example for a function named Load starts with ExampleLoad. An example for a method named Validate on a type Settings starts with ExampleSettings_Validate.
Here is how a realistic package looks with examples:
// Package config provides utilities for loading and validating YAML settings.
// It supports environment variable overrides and strict schema checking.
package config
// Settings holds the parsed application configuration.
type Settings struct {
Port int
Debug bool
LogPath string
}
// Validate checks required fields and returns an error if any are missing.
func (s *Settings) Validate() error {
// check port range
// verify log path exists
// return nil if all checks pass
}
// ExampleLoad demonstrates how to read a configuration file.
func ExampleLoad() {
// create a temporary YAML file for testing
// call Load with the file path
// print the parsed port number
// output: 8080
}
Example functions run with go test. The // output: comment tells the test runner what to expect on standard output. If the actual output does not match, the test fails. This keeps documentation accurate. If you change the function behavior and forget to update the example, the test suite catches it. Examples are executable documentation. Run them or lose them.
Pitfalls and compiler quirks
The documentation toolchain is unforgiving about structure. The most common mistake is placing a blank line between the comment and the declaration. The parser treats the comment as unrelated. You will see empty documentation when you run go doc. The compiler does not warn you. It simply omits the text.
Another frequent issue is missing package comments. If you run go doc ./mypackage and the package has no top-level comment, the toolchain prints a warning: go doc: no documentation found for package "example.com/mypackage". You fix it by adding a // Package mypackage provides... comment to any file in the directory.
Local documentation tools have evolved. The original godoc server is deprecated. It required a separate binary and a local web server. Modern workflows use go doc for terminal output and pkg.go.dev for public hosting. The pkg.go.dev site automatically crawls public repositories. It requires a valid module path in go.mod and a version control system like Git. If your repository lacks a go.mod file, the site cannot resolve the package. You will see a 404 or a module not found error when trying to view the docs.
Capitalization mistakes also break visibility. If you name a function parseConfig instead of ParseConfig, it becomes unexported. The documentation tool will not show it. External packages cannot import it. The compiler enforces this at compile time, but the documentation tool enforces it at render time. Both systems agree on the same rule.
The toolchain expects consistency. Break the pattern and your documentation disappears.
When to use which tool
Use go doc when you are debugging locally and need quick access to function signatures and comments without leaving the terminal. Use pkg.go.dev when you publish a public library and want a stable, versioned documentation site that handles cross-references and search automatically. Use the go test -run=Example command when you want to verify that your documentation examples still match the actual runtime output. Use third-party generators like swag or godoc alternatives only when you need custom HTML themes or offline documentation archives that the standard toolchain does not provide.
Pick the tool that matches your audience. Local debugging gets go doc. Public libraries get pkg.go.dev.