go-functional-options — Claude Code skill: Go options pattern
A skill that walks you through functional options for Go constructors with optional settings. Useful once a New* function takes three or more optional parameters.
npx skills add cxuu/golang-skills --skill go-functional-options -a claude-codeWhat go-functional-options does
The skill lays out the functional options pattern: an opaque Option type records settings in an internal struct, and the constructor takes a variadic list of them, applying each over the defaults. It covers the core pieces, a side-by-side comparison with a config struct, and a checklist.
The important part is the unexported apply method on the Option interface. It keeps options from other packages out, and that is deliberate. The skill also explains why the interface beats plain closures: options stay comparable in tests, can implement fmt.Stringer, and show up in documentation.
A comparison table tells you when a config struct wins instead — fewer than three options, settings that rarely change, or internal APIs only. In those cases the pattern just adds boilerplate. The bundled references/OPTIONS-VS-STRUCTS.md goes into hybrid APIs and the full interface-based implementation.
What it helps with
- design a
New*constructor with three or more optional parameters - add a new setting to a public API without breaking existing calls
- stop passing default values at every call site
- compare options in tests and mocks
- decide between functional options and a config struct
Example prompts for the agent
- Design a
NewServerconstructor with functional options for timeouts and a logger NewClientalready takes five optional parameters — rewrite it with the options pattern- Help me choose between a config struct and functional options for this API
How to install go-functional-options
1Skills CLI (Vercel)
npx skills add cxuu/golang-skills --skill go-functional-options -a claude-code2Manually: put the files in place
~/.claude/skills/go-functional-options/SKILL.mdCopy the whole skill folder; for one project use .claude/skills/go-functional-options/
1Skills CLI (Vercel)
npx skills add cxuu/golang-skills --skill go-functional-options -a codex2Manually: put the files in place
.agents/skills/go-functional-options/SKILL.mdFor all projects use ~/.agents/skills/
1Skills CLI (Vercel)
npx skills add cxuu/golang-skills --skill go-functional-options -a cursor2Manually: put the files in place
.cursor/skills/go-functional-options/SKILL.mdCursor also reads .agents/skills/ and .claude/skills/
1GitHub CLI
gh skill install cxuu/golang-skills go-functional-options2Manually: put the files in place
.github/skills/go-functional-options/SKILL.md1Skills CLI (Vercel)
npx skills add cxuu/golang-skills --skill go-functional-options -a gemini-cli2Platform CLI
gemini skills install https://github.com/cxuu/golang-skills --path skills/go-functional-optionsManually: put the files in place
.devin/skills/go-functional-options/SKILL.mdThe legacy .windsurf/skills/ path still works
Skills CLI (Vercel)
npx skills add cxuu/golang-skills --skill go-functional-options -a opencodeClaude.ai
Zip the folder and upload it in Settings → Capabilities → Skills
Step by step, with commands for each platform: How to install skills in Claude Code: five ways
Questions about go-functional-options
How do I install go-functional-options in Claude?
Run npx skills add cxuu/golang-skills --skill go-functional-options -a claude-code. The skill lands in ~/.claude/skills/go-functional-options/SKILL.md.
What does go-functional-options do?
It guides Go constructor and factory design with optional configuration: an options struct, an Option interface with an apply method, and With* constructors.
How do functional options differ from a config struct?
Options extend by adding new With* functions and skip passing defaults. A struct is simpler to set up, but adding a field can break callers, so the skill recommends options once you have three or more.
Source text
SKILL.md · Apache-2.0
---
name: go-functional-options
description: Use when designing a Go constructor or factory function with optional configuration — especially with 3+ optional parameters or extensible APIs. Also use when building a New* function that takes many settings, even if they don't mention "functional options" by name. Does not cover general function design (see go-functions).
---
# Functional Options Pattern
Functional options is a pattern where you declare an opaque `Option` type that records information in an internal struct. The constructor accepts a variadic number of these options and applies them to configure the result.
## Resource Routing
- `references/OPTIONS-VS-STRUCTS.md` - Read when choosing between config structs and functional options, implementing the full interface-based option pattern, or evaluating hybrid constructor APIs.
## When to Use
Use functional options when:
- **3+ optional arguments** on constructors or public APIs
- **Extensible APIs** that may gain new options over time
- **Clean caller experience** is important (no need to pass defaults)
## The Pattern
### Core Components
1. **Unexported `options` struct** - holds all configuration
2. **Exported `Option` interface** - with unexported `apply` method
3. **Option types** - implement the interface
4. **`With*` constructors** - create options
### Option Interface
```go
type Option interface {
apply(*options)
}
```
The unexported `apply` method ensures only options from this package can be used.
## Comparison: Functional Options vs Config Struct
| Aspect | Functional Options | Config Struct |
|--------|-------------------|---------------|
| **Extensibility** | Add new `With*` functions | Add new fields (may break) |
| **Defaults** | Built into constructor | Zero values or separate defaults |
| **Caller experience** | Only specify what differs | Must construct entire struct |
| **Testability** | Options are comparable | Struct comparison |
| **Complexity** | More boilerplate | Simpler setup |
**Prefer Config Struct when**: Fewer than 3 options, options rarely change, all options usually specified together, or internal APIs only.
## Why Not Closures?
The interface approach is preferred over closure-only options because:
1. **Testability** - Options can be compared in tests and mocks
2. **Debuggability** - Options can implement `fmt.Stringer`
3. **Flexibility** - Options can implement additional interfaces
4. **Visibility** - Option types are visible in documentation
## Quick Reference
```go
// 1. Unexported options struct with defaults
type options struct {
field1 Type1
field2 Type2
}
// 2. Exported Option interface, unexported method
type Option interface {
apply(*options)
}
// 3. Option type + apply + With* constructor
type field1Option Type1
func (o field1Option) apply(opts *options) { opts.field1 = Type1(o) }
func WithField1(v Type1) Option { return field1Option(v) }
// 4. Constructor applies options over defaults
func New(required string, opts ...Option) (*Thing, error) {
o := options{field1: defaultField1, field2: defaultField2}
for _, opt := range opts {
opt.apply(&o)
}
// ...
}
```
### Checklist
- [ ] `options` struct is unexported
- [ ] `Option` interface has unexported `apply` method
- [ ] Each option has a `With*` constructor
- [ ] Defaults are set before applying options
- [ ] Required parameters are separate from `...Option`
## Related Skills
- **Interface design**: See [go-interfaces](../go-interfaces/SKILL.md) when designing the `Option` interface or choosing between interface and closure approaches
- **Naming conventions**: See [go-naming](../go-naming/SKILL.md) when naming `With*` constructors, option types, or the unexported options struct
- **Function design**: See [go-functions](../go-functions/SKILL.md) when organizing constructors within a file or formatting variadic signatures
- **Documentation**: See [go-documentation](../go-documentation/SKILL.md) when documenting `Option` types, `With*` functions, or constructor behavior
### External Resources
- [Self-referential functions and the design of options](https://commandcenter.blogspot.com/2014/01/self-referential-functions-and-design.html) - Rob Pike
- [Functional options for friendly APIs](https://dave.cheney.net/2014/10/17/functional-options-for-friendly-apis) - Dave Cheney
© cxuu · Apache-2.0 · cxuu/golang-skills