go-ordered-map

A generic Go library for maps that preserve key insertion order, with constant-time operations and built-in JSON/YAML support.

Library
Go
vv2.1.8
676stars
Apache License 2.0

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
41/100Fair
Development Activity0
Maintenance20
Community56
Maturity60
Momentum28

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
76/100Good
Architecture78
Code Quality92
Innovation68
Learning Curve65

go-ordered-map provides a generic OrderedMap type for Go that behaves like a standard map but remembers the order in which keys were inserted, similar to Python’s collections.OrderedDict. All core operations — Get, Set, Delete, and iteration — run in constant time, backed by a doubly-linked list paired with a standard map for O(1) lookups.

The library supports bidirectional iteration from either the oldest or newest key without extra memory copies, native Go 1.23 range-over-func iterators, and drop-in JSON and YAML marshalling/unmarshalling that preserves key order through custom Marshaler/Unmarshaler implementations.

What You Get

  • A generic OrderedMap[K, V] type usable with any comparable key and any value type
  • Constant-time Get, Set, Delete, and Move operations backed by a map plus a doubly-linked list
  • Bidirectional iteration via Oldest()/Newest() pair traversal or native Go 1.23 iter.Seq/iter.Seq2 iterators
  • Built-in JSON and YAML marshalling/unmarshalling that preserves key order
  • Capacity hints and initial-data options via WithCapacity and WithInitialData

Common Use Cases

  • Preserving JSON object key order when re-serializing config or API payloads
  • Implementing LRU-style caches that need O(1) move-to-front/move-to-back semantics
  • Building deterministic serialization output for reproducible builds or diffable configs
  • Maintaining ordered YAML documents such as CI pipeline definitions

Under The Hood

Architecture The package is a single flat Go module (orderedmap) built around one core type, OrderedMap[K, V], defined in orderedmap.go: a map[K]*Pair[K, V] for O(1) lookups paired with a doubly-linked list from bahlo/generic-list-go that tracks insertion order, so every pair carries both a map entry and a list element. json.go and yaml.go each add marshalling behavior as separate files that implement the standard library’s Marshaler/Unmarshaler interfaces by walking the same linked list from Oldest() to Newest(), so the core data structure has no knowledge of serialization concerns — a clean, if minimal, separation for a package this size. There are no internal layers or abstractions beyond this because the problem domain doesn’t call for them; changing the underlying list implementation would only touch orderedmap.go.

Tech Stack Written in Go, requiring Go >= 1.23 to use generics and the iter.Seq/iter.Seq2 range-over-func iterators introduced in that release (an older v2.1.8 tag exists for Go < 1.23, and a v1 branch for pre-generics Go < 1.18). Dependencies are narrowly scoped to the job: bahlo/generic-list-go for the generic doubly-linked list, buger/jsonparser and mailru/easyjson’s jwriter for low-allocation JSON encode/decode, and gopkg.in/yaml.v3 for YAML support. Tests depend on stretchr/testify. There’s no build/deploy tooling beyond a Makefile and CircleCI configuration — this is a library, not a service.

Code Quality Test coverage is extensive relative to the implementation size: orderedmap_test.go, json_test.go, and yaml_test.go together with dedicated json_fuzz_test.go and yaml_fuzz_test.go files (using Go’s native fuzzing support) total over 1,500 lines against roughly 600 lines of implementation. .golangci.yml enables a wide set of linters (errcheck, errorlint, gocognit, goconst, dupl, funlen, and more) with disable-all: true as the baseline, meaning only explicitly chosen checks run — a deliberate, curated lint policy rather than defaults. CircleCI runs the suite on every push. Error handling is explicit and typed via a dedicated KeyNotFoundError[K] rather than sentinel errors or panics for expected failure paths.

API Design The public API deliberately mirrors familiar Go idioms: Load/Store are provided as aliases for Get/Set to match sync.Map’s naming, and iteration follows the container/list pattern of Oldest()/Next() and Newest()/Prev(). Construction uses a small functional-options pattern (WithCapacity, WithInitialData, WithDisableHTMLEscape) layered on a single New[K, V](options ...any) constructor, so getting started requires only one import and one call. Every exported type and method carries a godoc comment, and the README documents each feature with a runnable example plus an explicit comparison against four alternative ordered-map implementations, naming the specific tradeoff (linear deletes, goroutine-leaking channel iteration) each one avoids.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search