structs
Reflection-based Go utilities for converting structs to maps, slices, and field-level metadata without hand-written boilerplate.
Repository Health
Technical Analysis
structs is a small, dependency-free Go library built on top of the standard reflect package to make working with struct values less repetitive. It exposes a single Struct type (and matching package-level functions) that can turn any struct into a map[string]interface{}, a []interface{} of its values, or a list of field names — driven entirely by struct field tags rather than hand-written conversion code.
Field-level behavior is controlled through a structs tag with options like renaming a key, skipping a field with -, flattening a nested struct’s fields into the parent map, stringifying a field via its Stringer implementation, or skipping empty values with omitempty. A companion Field type gives per-field access for reading, setting, or zeroing individual struct fields through reflection, plus zero-value inspection helpers (IsZero, HasZero) for entire structs. The project has been archived by its author since 2018 but remains widely used and stable for its narrow scope.
What You Get
structs.Map(s)/New(s).Map()— convert any struct to amap[string]interface{}, recursing into nested structs, slices, and maps of structsstructs.Values(s)— flatten a struct’s field values into a[]interface{}in declaration order, including embedded struct fieldsstructs.Fields(s)/Names(s)— enumerate a struct’s exported fields or just their names, honoring-tag exclusions- Tag-driven behavior via the
structsstruct tag: custom key names,omitempty,omitnested,flatten, andstring(uses a field’sStringerimplementation) Fieldtype for per-field access —Value(),Set(),Zero(),IsZero(),IsEmbedded(),IsExported(), and tag lookups on a single struct fieldIsZero(s)/HasZero(s)to check whether all or any fields of a struct hold their zero value
Common Use Cases
- Serializing internal struct-based models to
map[string]interface{}for JSON-like APIs, template contexts, or logging without writing a marshaler by hand - Building generic configuration or settings systems that need to introspect arbitrary struct shapes at runtime
- Flattening nested config or DTO structs into a single flat map for form population, key-value stores, or environment-variable style access
- Validating that required struct fields were actually populated by checking
IsZero/HasZerobefore using a value - Writing generic reflection-based tooling (ORWs, CLI flag binders, template engines) that needs to walk arbitrary struct fields uniformly
Under The Hood
Architecture
The package is deliberately small and single-purpose: structs.go defines a Struct type that wraps a raw interface value, its reflect.Value, and a configurable tag name, while field.go defines a matching Field type for single-field access, and tags.go provides a tiny tag-parsing helper shared by both. Every package-level function (Map, Values, Fields, Names, IsZero, HasZero) is a thin wrapper that constructs a Struct via New() and delegates to the corresponding method, keeping the functional and object-oriented entry points in lockstep. The most structurally interesting piece is the recursive nested() helper in structs.go, which walks structs, slices, arrays, and maps of structs to build the recursive map output for Map()/FillMap() — a change to that function’s traversal rules is the one place that could ripple across most of the package’s behavior.
Tech Stack
Written in pure Go with zero third-party dependencies — only the standard library (reflect, fmt, errors, strings) is imported. It predates Go modules, so there is no go.mod; consumers pull it via go get and GOPATH-style vendoring. CI runs on Travis across several Go 1.x versions plus tip, with coverage reported through goveralls, and installation/build tooling is otherwise absent since the package is a plain importable library with no binaries or build steps of its own.
Code Quality
Test coverage is extensive relative to the package’s size: structs_test.go alone is roughly 1,450 lines covering close to fifty test functions, complemented by a dedicated field_test.go, a small tags_test.go, and a structs_example_test.go of runnable, doc-linked Example functions. Error handling uses explicit sentinel errors (errNotExported, errNotSettable) rather than panics for the mutable Field.Set() path, though several read-path functions still panic on invalid struct kinds by design, as documented in their doc comments. Every exported type and function carries a godoc comment, and naming follows standard Go conventions throughout; there is no dedicated linter configuration, consistent with a project of this era, but the code is gofmt-conformant.
API Design
The library’s ergonomics come from mirroring the same operation as both a package-level function (structs.Map(s)) and a method on a constructed Struct (structs.New(s).Map()), so callers can reach for the one-off form or the reusable form without learning two different APIs. Tag options (omitempty, omitnested, flatten, string, custom key names) compose the way encoding/json tags do, which keeps the learning curve low for anyone who has used Go’s standard marshaling conventions, and the Field type extends that same tag-driven model down to single-field reads and writes.
Used by 5 apps in this directory
Coder
Devops · Developer Tools · Code Editors
Self-hosted cloud development environments and AI coding agents — defined in Terraform, connected via WireGuard, automatically shut down when idle.
Hanko
Security · Authentication
Open source, self-hostable authentication platform with passkeys, SAML SSO, and OAuth — the privacy-first alternative to Auth0 and Clerk.
Navidrome
File Storage
Run your own personal Spotify — stream your entire music collection from any device, anywhere, forever.
Space Cloud
Devops · Authentication
Kubernetes-native serverless platform that generates instant GraphQL and REST APIs for any database with built-in auth and real-time subscriptions
Traefik
Devops · Automation · Security
A cloud-native reverse proxy and load balancer that auto-configures itself from Docker, Kubernetes, and other orchestrators — zero manual routing required.