deniz.in

Markets

Weather

Loading weather

· via dev.to (home feed)

Go 1.27's stdlib uuid package replaces google/uuid in four steps, with one NULL trap

Go 1.27 ships a standard-library uuid package covering v4 and v7. A dev.to walkthrough details the four-step migration off google/uuid and the nullable database column that now fails at runtime.

Go 1.27's stdlib uuid package replaces google/uuid in four steps, with one NULL trap

What the new package covers

Go 1.27, released on 2026-08-19, added a uuid package to the standard library; the release notes sum it up in a single line as generating and parsing UUIDs. According to a dev.to walkthrough, the import path is simply uuid and the API is intentionally small, built on RFC 9562: a comparable UUID type backed by a 16-byte array, New() for general use, NewV4() with 122 random bits, and NewV7() pairing a 48-bit millisecond timestamp with at least 62 random bits. Parse, MustParse, Nil() and Max() round out the package, alongside String, Compare, MarshalText, UnmarshalText and AppendText methods.

The dev.to author notes that Parse accepts the same forms google/uuid handles — hyphenated strings, curly-braced variants, the urn:uuid: prefix, and 32 bare hex digits in either case — so values already stored in databases keep parsing. Left out are the version 1, 3, 5 and 6 constructors, Version() and Time() methods, MarshalBinary, and a NullUUID type. The write-up points to the accepted proposal, discussed in golang/go#62026, as the record of why the surface stayed this small.

Bump the go directive before anything else

The first migration step is running go mod edit -go=1.27 before touching any import. The compiler will happily let you import uuid while go.mod still declares go 1.26, but Go 1.27 runs the stdversion vet check by default during go test. Per the dev.to post, that check flags standard-library symbols that are newer than the Go version in effect for the referring file, determined by the go directive plus any build tags on the file — so a skipped bump means go build succeeds while go test fails, locally and in CI.

Let the compiler find the breaks

With the import changed to uuid, building the module surfaces the differences. Two errors show up in nearly every codebase: NewV7() now returns only a UUID rather than a UUID and an error, and Nil and Max are functions instead of variables, so a comparison against uuid.Nil fails to compile until parentheses are added. Code that relied on id.Time() or id.Version() has to reimplement them; both are fixed bit positions in RFC 9562, with the version in the high nibble of byte 6 and a v7 timestamp in the first 48 bits, expressed in milliseconds.

Migrate package by package with a cast

Large repositories do not need a single sweeping change. Because the google/uuid and standard-library types share [16]byte as their underlying type, a direct conversion between them copies 16 bytes and nothing else, so packages can migrate incrementally behind small conversion helpers at the seam. JSON output is unchanged as well, since both implementations marshal to the lowercase hyphenated text form. The author also highlights that NewV7 values increase monotonically unless the system clock moves backwards, and that Compare orders by big-endian bytes, so uuid.UUID.Compare drops straight into slices.SortFunc — giving creation order without a separate created_at sort key, as long as clocks behave.

The NULL catch

The subtle failure sits in database code. The standard-library type defines no Scan or Value methods, but Go 1.27's database/sql handles uuid.UUID natively: the default parameter converter emits the string form for writes, and Rows.Scan lists *uuid.UUID as a supported destination, accepting either a UUID's string representation or a 16-byte slice. Rows with real values work unchanged. A NULL column does not. google/uuid's Scan quietly left the destination untouched for a nil source, so fresh variables stayed uuid.Nil; the stdlib path, as the dev.to analysis describes, falls through to a generic unsupported-Scan error for NULL and fails inside uuid.Parse for empty strings. Nothing catches this at compile time, and a test suite that only seeds child rows will pass. The fix is sql.Null[uuid.UUID] — the generic sql.Null[T] has shipped since Go 1.22 — scanning into it and copying the value only when Valid is set.

Why it matters

The dev.to author opens by observing how common github.com/google/uuid is in Go services' go.mod files, and its last tagged release, v1.6.0, dates to January 2024. A standard-library replacement for the common v4 and v7 cases removes one widely used external dependency from the graph, trimming supply-chain surface and upgrade churn. The migration is mostly mechanical and compiler-guided, but the NULL-scan behavior change is the kind of semantic difference that survives code review and CI and then breaks in production on the first row without a value — which is exactly why the author singles it out as the one case to test deliberately.

  • #golang
  • #go-1-27
  • #uuid
  • #standard-library
  • #dependencies