What is a Go package comment, and why do large packages keep it in doc.go?
answer
- the first thing a stranger reads
- immediately above the package clause
- one file, not several
- the first sentence becomes the summary
- a conventional filename, not a required one
basics
~20 sA package comment is the comment block immediately above a package clause, and it is the first thing a reader sees on the package's documentation page. One file should carry it; a long one usually lives in doc.go.
solid answer
~40 sThe package comment sits directly above the `package` clause, with no blank line, and becomes the opening prose of the package's documentation page — for most readers it is the only onboarding they get. Convention is to begin `Package ledger …` with a first sentence that stands alone, because that sentence is used as the package's one-line summary in listings. Exactly one file in the package should carry it; when it grows past a paragraph, the usual home is a `doc.go` holding just the comment and the package clause, which keeps a long overview out of an implementation file and out of that file's diffs. `doc.go` is pure convention, not a name the toolchain requires. For a `package main`, the same comment documents the command — what it does, its flags and its usage.
code
go · 7 lines// Package ledger records double-entry postings for the billing service.
//
// A caller opens a book with [Open], appends postings to it, and closes the
// book to flush. Every posting names two accounts and must balance to zero.
//
// A book returned by [Open] is not safe for concurrent use.
package ledgergo deeper
Know where the package comment goes — directly above the package clause — and the conventional opening, Package name followed by a verb phrase, in one sentence that reads on its own.
Explain why the first sentence is extracted as a summary, why exactly one file should carry the comment, and that doc.go is a convention for keeping a long overview out of implementation files.
Show the review habit: reading the package page as a stranger, checking that it names the entry point and the caller's obligations, and treating a renamed entry point as a change to the package comment too.
Own what a package landing page must contain before your team publishes it for others to import, and accept that the page, not the README, is what importers will actually read.
## The package comment is the landing page Every Go package's documentation opens with the **package comment**: the comment group placed immediately above the `package` clause, with no blank line between them. Everything below it on the rendered page is generated — the index, the signatures, the per-symbol prose. The package comment is the only place where an author gets to explain the package as a whole: what it is for, what the central type is, which call to make first, and what the caller is responsible for. This matters more in Go than the effort usually spent on it suggests, because a package is consumed by import path. Someone adding your package to their build typically never opens your repository — they read the rendered page, copy a call, and move on. If the first paragraph does not orient them, nothing else will. ## The conventional shape Start with `Package <name>` and a verb phrase, as a complete sentence: ```go // Package ledger records double-entry postings for the billing service. ``` Two reasons. First, the **first sentence is extracted as the summary** shown next to the package in listings and search results, so it has to read correctly with no surrounding context — `// This package handles ledgers.` becomes a summary beginning with *This*, referring to nothing. Second, it sets the subject explicitly, which matters when the same sentence appears in a list of thirty packages. After the summary, a package comment for anything non-trivial usually continues with: a short paragraph naming the main type and the entry point, headings for the sections a stranger needs, one small indented example of the smallest working use, and a note on concurrency safety if callers will share a value across goroutines. Keep the prose about **this** package's job; the compatibility policy of the wider module, and how large its exported surface should be, are separate concerns from what the opening paragraph says. ## Why doc.go A package comment of two sentences can live above the `package` clause of any file. Once it grows to a screen of prose with headings and an example, putting it above a real implementation file has two costs: it buries the code under an essay, and every edit to that overview churns the diff of a file people are also editing for behaviour. The convention is a file named **doc.go** whose entire content is the package comment plus the package clause — no imports, no declarations. Two things follow from that. `doc.go` is a **convention only**: the toolchain has no special handling for the name, and a package comment in any other file works identically. And the package comment should live in exactly **one** file — putting one above the package clause of several files in the same package is a documented mistake, and you should not depend on how the tools combine them. Concentrating it in `doc.go` makes that rule easy to hold: there is one obvious place to look, and one place to edit. ## Commands A `package main` also has a package comment, and there it documents **the command** rather than a library API: the one-line purpose, the usage line, the flags, and the exit behaviour. That prose is what a reader gets for a tool whose exported identifiers are irrelevant to them. When you do want to read a command's symbols as if it were a normal package, `go doc` needs `-cmd` to show them. ## What good looks like in review The test that catches most problems is to read the page as a stranger and ask three questions: does the first sentence tell me whether this package solves my problem; is there a call I can copy; and does it tell me what I must do that the type signature cannot say — close something, avoid sharing something, call one function before another. If a reviewer has to open the source to answer any of those, the package comment is not finished, however good the per-function comments are. The opposite failure is a package comment that has drifted: it describes the constructor the package had two releases ago, or names a type that has since been split. Nothing in the toolchain checks prose against code, so this is a review habit rather than a tool — when an entry point changes, the package comment is part of the change.
- What should the first sentence of a package comment do?Stand completely alone. It is extracted as the package's one-line summary in listings and search results, so it has to identify the package by name and say what it is for: `Package ledger records double-entry postings for the billing service.` A first sentence beginning `This package…` becomes a summary whose subject is missing wherever it is quoted.
- What does the doc comment on a `package main` document?The command itself — its purpose, usage line, flags and behaviour — because the exported identifiers of a main package are not what any reader wants. That prose is the manual page for the tool. If you do want to read a command's symbols as though it were an ordinary package, `go doc` takes a `-cmd` flag for exactly that.
- What happens if two files in the same package each carry a package comment?It is a mistake, and not something to rely on the tools resolving sensibly. The convention is exactly one package comment per package, which is precisely why a `doc.go` is useful: there is one obvious place for it, so a second one is easy to spot in review and easy to fold into the first.
- Does the toolchain treat a file named doc.go specially?No. The name is convention alone; a package comment above the package clause of any file in the package works identically. The value of doc.go is human: it keeps a long overview out of an implementation file, keeps that file's diffs about behaviour, and gives reviewers one predictable place to look for the package's opening prose.
saying these in an interview costs you the question
- Puts the package comment above the import block instead of the package clause
- Writes the package overview only in a README and leaves the page empty
- Opens with This package instead of naming the package
- Scatters package comments across several files in the package
- Thinks doc.go is a filename the toolchain requires
- Leaves the package comment describing an entry point that was renamed