Skip to content
Nullable & Optional Values

Nullable & Optional Values

The nulls and optional packages model fields that can be absent — typed alternatives to raw pointers and to sql.Null*.

nulls.Null[T]

nulls.Null[T] wraps any type T with a Valid flag and interoperates with JSON, database/sql, and database/sql/driver:

type Null[T any] struct {
	V     T
	Valid bool
}
var _ json.Marshaler = Null[int]{}
var _ json.Unmarshaler = (*Null[int])(nil)
var _ sql.Scanner = (*Null[int])(nil)
var _ driver.Valuer = Null[int]{}

New(v) builds a valid value. In JSON, an invalid Null marshals to null and a JSON null unmarshals to an invalid instance; non-null values marshal/unmarshal as the wrapped type — including time values, slices, pointers, and structs. Through sql, Scan(nil) clears the value and Value() produces nil for an invalid instance, so nullable database columns round-trip without special handling:

type User struct {
	ID        int64        `db:"id"`
	AvatarURL nulls.Null[string] `db:"avatar_url"`
}

optional.Option[T]

optional.Option[T] is the same idea as a plain value with a presence flag, and Some(v)/None[T]() build it:

type Option[T any] struct {
	Value T
	Valid bool
}
opt := optional.Some("pending")
// or
opt := optional.None[string]()

if opt.Valid {
	// ...
}

Note that the optional package is still a stub: its MarshalJSON, UnmarshalJSON, and text/binary encoding methods currently panic. Use nulls.Null[T] when a nullable value must cross a JSON or database boundary.