go
50 lines · 7 steps
The functional options pattern in Go
Configure a struct with any subset of settings by passing composable functions instead of a giant argument list.
Explained by
highlit
1package config
2
3import "time"
4
5type ServerConfig struct {
6 Host string
7 Port int
8 ReadTimeout time.Duration
9 WriteTimeout time.Duration
10 MaxConnections int
11 TLSEnabled bool
12 AllowedOrigins []string
13}
14
15type Option func(*ServerConfig)
16
17func WithHost(host string) Option {
18 return func(c *ServerConfig) { c.Host = host }
19}
20
21func WithPort(port int) Option {
22 return func(c *ServerConfig) { c.Port = port }
23}
24
25func WithReadTimeout(d time.Duration) Option {
26 return func(c *ServerConfig) { c.ReadTimeout = d }
27}
28
29func WithMaxConnections(n int) Option {
30 return func(c *ServerConfig) { c.MaxConnections = n }
31}
32
33func WithTLS(enabled bool) Option {
34 return func(c *ServerConfig) { c.TLSEnabled = enabled }
35}
36
37func WithAllowedOrigins(origins ...string) Option {
38 return func(c *ServerConfig) {
39 c.AllowedOrigins = append([]string(nil), origins...)
40 }
41}
42
43func (base ServerConfig) With(opts ...Option) ServerConfig {
44 clone := base
45 clone.AllowedOrigins = append([]string(nil), base.AllowedOrigins...)
46 for _, opt := range opts {
47 opt(&clone)
48 }
49 return clone
50}
01 / 01
STEP 01
‹ swipe to step through ›
Walkthrough
Space play
←→ step
click any line
Three takeaways
- 1Functional options let callers set only the fields they care about while everything else keeps its zero or default value.
- 2Returning closures over a shared config pointer keeps each option small, self-contained, and independently testable.
- 3Copying slices during a clone prevents callers from mutating each other's shared backing arrays.
Related explainers
go
func (h *WebhookHandler) HandleBatch(c *gin.Context) { var payload BatchWebhookPayload if err := c.ShouldBindJSON(&payload); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "invalid payload"})
Handling batched webhooks in Gin
webhooks
signature-verification
job-queue
Intermediate
7 steps
go
package admin import ( "net/http"
Building a protected admin area in Gin
routing
middleware
authentication
Intermediate
6 steps
go
package middleware import ( "errors"
Capping request body size in Gin
middleware
request limits
error handling
Intermediate
5 steps
go
package batch import "fmt"
Splitting a slice into batches in Go
generics
slices
error-handling
Intermediate
6 steps
javascript
import { useState, useRef } from "react"; export function TagInput({ initialTags = [], onChange }) { const [tags, setTags] = useState(initialTags);
Building a tag input in React
controlled-inputs
state-management
keyboard-handling
Intermediate
8 steps
go
package security import ( "crypto/hmac"
Signing and verifying payloads with HMAC in Go
hmac
cryptography
authentication
Intermediate
5 steps
Share this explainer
Here's the card — post it anywhere.
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code
Embed this explainer
Drop the interactive walkthrough into a blog or docs. Views never cost a credit.
<iframe src="https://highlit.co/explainers/the-functional-options-pattern-in-go-explained-go-be23/embed?autoplay=1" width="100%" height="520" loading="lazy" style="border:0"></iframe>
Autoplay is on by default — add ?autoplay=0 to start paused.