go 21 lines · 1 tab

Lazy init of expensive clients with sync.Once

Leah Thompson Jan 2026
1 tab
package deps

import "sync"

type Lazy[T any] struct {
  once sync.Once
  v    T
  err  error
  init func() (T, error)
}

func NewLazy[T any](init func() (T, error)) *Lazy[T] {
  return &Lazy[T]{init: init}
}

func (l *Lazy[T]) Get() (T, error) {
  l.once.Do(func() {
    l.v, l.err = l.init()
  })
  return l.v, l.err
}
1 file · go Explain with highlit

Some dependencies are expensive to initialize (TLS-heavy clients, large config loads, SDKs that fetch metadata). I use sync.Once to ensure initialization happens exactly once, even under concurrent access. The important detail is capturing the initialization error and returning it consistently; Once only runs the function once, even if it fails, so you need to decide whether failures should be cached or retried. For most services, caching is correct: if the dependency can’t initialize, the service should fail fast or degrade explicitly. The snippet below implements a lazy client with Client() that either returns the initialized client or the init error. This keeps call sites simple and prevents subtle races where two goroutines try to initialize the same global client simultaneously.


Related snips

Share this code

Here's the card — post it anywhere.

Lazy init of expensive clients with sync.Once — share card
Link copied