Accepted proposal: UUID in the Go standard library

It’s good to see that Go is finally getting uuid in the standard library. The proposal was accepted on April 8. I hadn’t been following the conversation in the thread and only found out about it from Cup o’ Go episode 154 .

google/uuid is usually one of the first extra imports I add to a Go service that talks to a database, so this one has felt overdue for years.

Python, Java, and C# have had native UUID support for years. I often use python -m uuid whenever I need a one-off UUIDv4, and Python 3.14+ added python -m uuid -u uuid7 to get UUIDv7s. So Go’s not having it in the stdlib has always felt odd to me.

The accepted API is much smaller than google/uuid. The thread landed on a package that covers the common cases and leaves the rest alone.

package uuid

type UUID [16]byte

func Parse(string) (UUID, error)
func MustParse(string) UUID

func New() UUID
func NewV4() UUID
func NewV7() UUID

func Nil() UUID
func Max() UUID

func (UUID) String() string
func (UUID) Compare(UUID) int
func (UUID) MarshalText() ([]byte, error)
func (UUID) AppendText([]byte) ([]byte, error)
func (*UUID) UnmarshalText([]byte) error

The package is uuid, not crypto/uuid, which makes more sense to me. The stdlib’s type UUID [16]byte matches google/uuid, so conversion basically requires a single cast. Parse accepts the same string forms as google/uuid: dashed strings, braces, urn:uuid: prefixes, and bare 32-character hex. If someone changes the import path and the code still compiles, it should still run.

The API keeps generation and parsing front and center. It adds NewV4() and NewV7(), keeps a plain New() for the common case, and leaves most of the inspection surface from google/uuid out.

I had expected New() to resolve to v7 because that is where most UUID discussion has moved over the last two years. Go went with v4 instead. v7 is better for insertion locality in B-tree indexes, which is great if you’re planning to use UUIDs as primary keys in Postgres or MySQL. But it also puts creation time in the ID and makes ordering visible.

id := uuid.New()   // v4 for now
pk := uuid.NewV7() // choose this on purpose

If your system benefits from v7, you’ll call NewV7() directly.

There’s no v1, v3, v5, v6, or v8 constructor. There’s no Version(), Time(), NodeID(), or other API for pulling fields back out of the bytes. The package is trying to set a common UUID type for Go and cover the common cases instead of absorbing every feature from the third-party packages.

There’s already a follow-up issue asking if Nil() should become Zero(). I would have picked Zero(), because nil means something specific in Go and [16]byte is not that. But the RFC calls it Nil, the existing Go packages call it Nil, and the rename issue is leaning toward decline.

The proposal is accepted, but there is no target Go release attached to it yet. But I’m hoping that it lands on 1.27.

§