hashstructure
A Go library for generating deterministic hash values from arbitrary structs, maps, and slices.
Repository Health
Technical Analysis
hashstructure is a small, dependency-free Go library that computes a deterministic uint64 hash for any Go value — including deeply nested structs, maps, slices, and arrays — using reflection to walk the value’s structure rather than requiring per-type marshaling code. Two values that are structurally equal always hash the same way regardless of map key ordering or how the value was constructed, which makes the library useful anywhere code needs to compare, cache, or deduplicate complex values without a full equality check or custom serialization.
Hashing behavior is customizable through struct tags (hash:"ignore", hash:"-", hash:"set", hash:"string") and through the Includable, IncludableMap, and Hashable interfaces, which let a type opt fields in or out of the hash, or override the hash computation entirely. The library ships two format versions — FormatV1, the original algorithm, and FormatV2, which fixes known hash-collision issues from v1 — so callers explicitly choose which collision-safety guarantees they want rather than having behavior change silently between releases.
What You Get
- A single
Hash(v, format, opts)entry point that works on any Go value through reflection — no per-type boilerplate to write or maintain - Struct tags (
hash:"ignore",hash:"-",hash:"set",hash:"string") for declarative, field-level control over what gets hashed and how HashOptionsfor swapping in a customhash.Hash64implementation, changing the struct tag name, and controlling nil/zero-value and zero-field handlingIncludable,IncludableMap, andHashableinterfaces so a type can dynamically decide per-field or per-entry inclusion, or override its hash computation entirely
Common Use Cases
- Detecting whether a config or resource struct has changed between reconciliation passes in an operator or controller loop
- Building cache keys for arbitrary in-memory values without hand-writing custom serialization
- Fingerprinting resource configuration blocks to detect drift, the pattern hashstructure was originally built for at HashiCorp
- Comparing unordered collections — slices tagged
hash:"set"— for equality regardless of element order
Under The Hood
Architecture hashstructure is organized as a single focused package split across three files: hashstructure.go holds the public Hash entry point and the internal walker that recursively traverses any Go value via reflect.Value, include.go defines the Includable/IncludableMap/Hashable extension interfaces, and errors.go isolates the two typed error values. The walker dispatches purely on reflect.Kind — numeric types are binary-written directly to a hash.Hash64, while structs, maps, slices, and arrays recurse into visit() and combine child hashes with either an ordered (hashUpdateOrdered) or XOR-based unordered (hashUpdateUnordered/hashFinishUnordered) combinator depending on whether ordering should affect the result. There’s no external state or dependency injection; the entire library is a pure function of (value, format, options), which keeps it trivially embeddable in any caller’s code path with no side effects to reason about.
Tech Stack The library has zero third-party dependencies — go.mod declares only the module path (github.com/mitchellh/hashstructure/v2) and a go 1.14 minimum, and every import (encoding/binary, fmt, hash, hash/fnv, reflect, time) comes from the standard library. Hashing defaults to FNV-64 (hash/fnv) but is fully swappable via HashOptions.Hasher for any hash.Hash64 implementation. CI (.github/workflows) runs a single go test ./… job on Go 1.15/ubuntu-latest — no build matrix, no lint step, no release automation beyond git tags.
Code Quality Test coverage is extensive relative to the library’s surface area: hashstructure_test.go exercises identity stability across 100 repeated hashes per case, cross-type equality/inequality, the ignore/set/string struct tags, nil-vs-zero-value handling, the Includable/IncludableMap/Hashable override interfaces, and explicit stringer-tag error cases, and hashstructure_examples_test.go provides runnable godoc examples with checked output. Error handling is explicit and typed (ErrNotStringer, ErrFormat implement the error interface rather than relying on bare fmt.Errorf, aside from one default-branch fallback). Naming is idiomatic Go throughout, exported identifiers carry doc comments, and there’s no evidence of a linter/formatter step in CI beyond implicit gofmt conventions.
API Design The public surface is a single function, Hash(v interface{}, format Format, opts *HashOptions), that works with zero configuration — passing nil for opts is valid and defaults to FNV-64 with a “hash” tag name. Customization is layered on through struct tags (hash:“ignore”, hash:”-”, hash:“set”, hash:“string”) that mirror the familiar encoding/json tag idiom, so Go developers already know the mental model. Deeper control is opt-in via three small interfaces (Includable, IncludableMap, Hashable) rather than required boilerplate, and the required FormatV1/FormatV2 parameter forces callers to make an explicit, documented choice about collision-safety semantics instead of silently changing hash output across versions.
Used by 2 apps in this directory
Filestash
File Storage
A self-hosted file management platform that unifies access to S3, SFTP, SMB, FTP, WebDAV, NFS, Git, SharePoint, and 20+ other storage backends through a single extensible web interface.
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.