How to Write Example Functions (Testable Examples) in Go

Write a function starting with Example followed by the target name and include an Output comment to create a testable Go example.

When docs need to prove themselves

You publish a package. The documentation looks solid. A user copies a snippet, runs it, and hits a panic. The example was written months ago. The API changed. The comment didn't catch the drift. Go provides a mechanism to make documentation runnable and verifiable. You write code that demonstrates the API, and the test runner executes it to ensure the output matches expectations. Example functions bridge the gap between static comments and regression tests. They show users how to use the code and guarantee the behavior stays consistent.

Examples are runnable documentation

Think of a cookbook where every recipe includes a photo of the finished dish. The book has a built-in camera that snaps a picture of your attempt and compares it to the reference. If the pictures don't match, the recipe is flagged as broken. Example functions work the same way. They serve as documentation for public APIs and act as tests that verify the output. The go test command treats functions with names starting with Example as special test cases. It compiles them, runs them, and captures their standard output. If the function ends with a // Output: comment, the runner compares the actual stdout against that string. A mismatch fails the test.

Examples are docs that run.

The minimal example

Here's the simplest testable example: a function starting with Example, a bit of code, and a comment declaring the expected output.

// ExampleHello demonstrates printing a greeting.
func ExampleHello() {
	// Call the function being documented.
	result := Hello("World")
	// Print the result so the test runner can capture it.
	fmt.Println(result)
	// Output: Hello, World!
}

How the runner works

The test runner scans the package for functions matching the Example prefix. It runs them in alphabetical order by name. The runner captures everything written to standard output. It strips the final newline from the output before comparing it to the // Output: comment. This means you don't need to include a trailing newline in the comment, even if fmt.Println adds one. The comparison is exact. Whitespace, capitalization, and newlines within the output must match the comment. If the output differs, the test fails and reports a diff. You'll see an error message like got: "Hello\n" want: "Hello" in the test output. This strictness prevents subtle bugs where the example looks correct in the docs but behaves differently at runtime.

The runner is strict. Trust the diff.

Naming and multiple examples

The naming convention determines where the example appears in the generated documentation. ExampleFoo documents a function, variable, or constant named Foo. ExampleFoo_Bar documents the Bar method on type Foo. You can provide multiple examples for the same function by adding a suffix. The suffix appears as a subheading in the docs.

Here's how to provide multiple examples for the same function using suffixes. The suffix appears in the generated docs.

// ExampleParseJSON demonstrates parsing a simple object.
func ExampleParseJSON() {
	// Parse valid JSON input.
	data, _ := ParseJSON(`{"name": "Alice"}`)
	fmt.Println(data.Name)
	// Output: Alice
}

// ExampleParseJSON_error demonstrates handling malformed input.
func ExampleParseJSON_error() {
	// Pass invalid JSON to trigger an error.
	_, err := ParseJSON(`{bad}`)
	// Print the error message for verification.
	if err != nil {
		fmt.Println(err)
	}
	// Output: invalid character 'b' looking for beginning of object key string
}

Realistic usage with context and errors

Real packages have types, methods, and error paths. Examples should demonstrate the full lifecycle, including error handling, because users will copy this code. Follow community conventions in examples. Pass context.Context as the first argument to functions that require it. Handle errors explicitly. Use gofmt to format the code; examples are code and must adhere to the same style rules.

Here's a realistic example showing a method call, context usage, and error handling.

// ExampleUser_Fetch demonstrates retrieving user data with context.
func ExampleUser_Fetch() {
	// Create a background context for the standalone example.
	ctx := context.Background()
	// Instantiate the user client.
	client := NewUserClient()
	// Call the method with context as the first parameter.
	user, err := client.Fetch(ctx, "u123")
	// Handle the error and print the result.
	if err != nil {
		fmt.Println("error:", err)
		return
	}
	fmt.Println(user.Name)
	// Output: Alice
}

Convention aside: context.Context always goes as the first parameter, conventionally named ctx. Functions that take a context should respect cancellation and deadlines. Examples should model this behavior by passing a context, even if it's just context.Background().

Pitfalls and strict output matching

The output comparison is exact. Whitespace, newlines, and capitalization must match the // Output: comment. If your code prints a trailing newline but the comment doesn't, the test fails. The test runner reports the failure with a diff showing the expected versus actual output. You'll see something like got: "Hello\n" want: "Hello" in the test output. This strictness prevents subtle bugs where the example looks right in the docs but behaves differently at runtime. Another pitfall is relying on non-deterministic output. If your example prints a timestamp or a random number, the test will flake. Example functions must be deterministic. Use fixed seeds or mock time if needed.

Determinism is mandatory. Randomness breaks examples.

Controlling output and verbosity

You can run only examples with go test -run Example. This is useful in CI pipelines to ensure documentation stays valid without running the full test suite. You can also write examples without a // Output: comment. These examples run and print nothing on success. Use this for examples that demonstrate side effects or where output is irrelevant, though this is rare. Most examples should verify output to provide value. The go doc tool extracts examples and displays them alongside the function signature. The suffix in the name becomes the heading in the docs. This makes examples the primary way users learn the API.

Decision matrix

Use an Example function when you want to document public API usage and guarantee the output matches the docs.

Use a Test function when you need to assert internal state, check error types, or test private helpers that don't produce stdout.

Use a Benchmark function when you need to measure execution time and memory allocation for performance-sensitive code.

Use a Fuzz function when you want to stress-test inputs by generating random data to find crashes or invariants.

Examples are docs that run. Tests are code that checks. Keep them separate.

Where to go next