Skip to content
tezvyn:
Menu

Go's Functional Options Pattern for Flexible APIs

Source: golang.designMediumHow cards are made

The functional options pattern uses functions to set optional struct fields, making APIs flexible and readable. It's common for complex constructors like servers or DB clients.

Why it exists

Go lacks named arguments and function overloading. This makes initializing a struct with many optional fields messy, often leading to constructors with long, confusing argument lists or requiring users to manually build a config struct. The functional options pattern provides a clean, extensible, and self-documenting API for this exact problem.

The mental model

Think of it as giving a list of instruction cards to a builder. Instead of a rigid blueprint, you hand over cards like "UsePort(8080)" or "WithTimeout(5s)". The builder applies whichever cards you provide, in any order, and uses sensible defaults for anything you didn't specify. This makes the initialization process flexible and the calling code highly readable.

How it works

First, you define an Option type as a function that accepts a pointer to your struct, e.g., type Option func(Server). Second, you create exported functions that return these Option functions. For instance, func WithPort(p int) Option { return func(s Server) { s.port = p } }. Finally, your constructor, like NewServer, accepts a variable number of options (...Option), creates a default struct, and then iterates through the provided options, applying each one to the struct before returning it.

When to use it

This pattern is ideal for public library APIs where you need to initialize complex objects. It allows you to add new configuration options in the future without breaking existing user code. Deprecating an option is as simple as making its function a no-op. The call site becomes very clear: NewClient(WithRetries(3), WithLogger(log.Default())).

When not to use it

For simple structs with few or no optional fields, this pattern is overkill and adds unnecessary boilerplate. The main drawback is the verbosity and code duplication required when multiple different structs need similar options; each struct requires its own distinct Option type and a full set of option-generating functions.

One canonical example

To create a server object, a user would call a constructor with a variable number of options: srv := NewServer(WithPort(8080), WithHost("localhost")). The NewServer function accepts ...Option, creates a default server struct, and then loops over the provided options to configure the instance. A call with no arguments, NewServer(), would simply return a server with all default values.

Interview question

What is a key benefit of employing Go's Functional Options pattern for configuring complex objects?

  • a.It eliminates the need for default values, simplifying object initialization.
  • b.It allows for the addition of new configuration settings without altering existing API call signatures.Correct
  • c.It guarantees that all configuration parameters are validated at compile time.
  • d.It significantly reduces the overall code verbosity compared to passing a dedicated configuration struct.
Why?

The card states that this pattern "allows you to add new configuration options in the future without breaking existing user code," making API evolution simpler. Option D is incorrect because the card mentions that the pattern can introduce "verbosity and code duplication" in certain scenarios, rather than universally reducing it.

Just read this? Test yourself on what you have been reading.

Read the original → golang.design

Put your scrolling time to good use

Learn one idea, try a quiz and save useful cards for revision. Tezvyn makes it easy to learn and stay current in your tech field, a few minutes at a time.

The iPhone app is on the way

We are building it. Until it lands, nothing here is held back from you: every interview card, your saved cards, streaks and the job board all work in Safari, plus hundreds of free practice quizzes of thirty questions each. Sign in and it all carries over to the app the day it arrives.

Want it as an icon? Tap Share at the bottom of Safari, then Add to Home Screen. It opens full screen and the cards you have read stay available offline.

Get it on Google PlayiPhone app coming soon

We are hiring for this. Open roles that interview on go — each one lists the topics its interview covers.

See open roles