copier

Reflection-based Go library for copying values between structs, slices, and maps with tag-driven field control.

Library
Go
vv0.4.0
6,177stars
MIT License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
42/100Fair
Development Activity8
Maintenance0
Community60
Maturity60
Momentum40

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
63/100Good
Architecture62
Code Quality68
Innovation65
Learning Curve55

Copier is a small, dependency-free Go library that copies data between structs, slices, and maps using reflection, matching fields and methods by name rather than requiring manual field-by-field assignment. It handles nested structs, embedded/anonymous fields, pointer dereferencing, and type conversion automatically, and integrates with database/sql’s Scanner and Valuer interfaces for working with nullable SQL types.

Struct tags (copier:"must", copier:"-", copier:"override", custom field names) and CopyWithOption settings (IgnoreEmpty, DeepCopy, CaseSensitive, custom converters, field name mappings) give fine-grained control over how individual fields are copied, making it a common choice for mapping between DTOs, ORM models, and API request/response types without writing boilerplate conversion code.

What You Get

  • Field-to-field and method-to-field copying based on matching names
  • Support for slice-to-slice, struct-to-slice, and map-to-map copying
  • Struct tags for enforcing (must), ignoring (-), and overriding fields
  • CopyWithOption controls: IgnoreEmpty, DeepCopy, CaseSensitive matching
  • Custom type converters and field name mappings for mismatched schemas
  • Built-in support for database/sql Scanner and Valuer interfaces

Common Use Cases

  • Mapping database ORM models to API response DTOs
  • Converting between versioned API request/response structs
  • Populating view models from domain models in web handlers
  • Cloning structs with select fields overridden via IgnoreEmpty/override tags
  • Bulk-copying slices of structs, e.g. entity lists to view-model lists

Under The Hood

Architecture The package is a flat, single-file implementation (copier.go plus errors.go) built around one recursive copier() function that inspects reflect.Value/reflect.Type pairs and dispatches by type kind (slice, map, struct, primitive), delegating scalar/pointer coercion, sql.Scanner/Valuer bridging, and TypeConverter lookup to a shared set() helper. Struct field introspection is memoized in a package-level deepFieldsMap guarded by sync.RWMutex to avoid repeated reflection walks on the same type. There’s no layering in the OOP sense — Copy/CopyWithOption are the only two public entry points, and everything else (copier, set, getFlags, parseTags, fieldByName, deepFields) is an unexported helper called recursively from that core function, so changes to the central dispatch logic ripple through every type-kind branch (slice, map, struct, pointer) at once.

Tech Stack A Go 1.13 module with zero external dependencies — only the standard library (reflect, database/sql, database/sql/driver, fmt, strings, sync, unicode). There’s no build tooling beyond go build/go test; CI (.github/workflows/tests.yml) runs go test across a matrix of Go 1.17 through 1.22 on Ubuntu and macOS. It ships as a plain importable package with no CLI, binary, ORM, or web framework involved — a pure reflection utility meant to be pulled into other Go codebases.

Code Quality The repo has an extensive test suite: a large primary copier_test.go alongside focused files for struct tags, type converters, benchmarks, case-insensitive matching, field-name mapping, and specific regression cases tied to GitHub issues — all using the standard library testing package with no external assertion library. Error handling mixes explicit error return values (e.g. ErrInvalidCopyDestination, ErrMapKeyNotMatch) with panic() for must-tagged fields unless nopanic is also set, which is a deliberate but sharp-edged design choice. Naming follows idiomatic Go conventions, and no generics are used despite Go 1.18+ appearing in the CI matrix — the library relies entirely on interface{} and reflection. No linter configuration or coverage reporting is visible in the repo.

API Design The public surface is intentionally minimal: two functions, Copy and CopyWithOption, cover nearly every use case, with a single Option struct (IgnoreEmpty, DeepCopy, CaseSensitive, Converters, FieldNameMapping, Must, NoPanic) providing progressive complexity rather than a sprawling function surface. Getting started requires no boilerplate — copier.Copy(&dst, &src) is a complete call — and the README documents every struct tag and option with runnable examples. Naming across tags (copier:"must", copier:"-", copier:"override") is consistent, though the default panic-on-must-tag behavior is a notable developer-experience sharp edge that requires opting into nopanic to get error-based handling instead of a runtime panic.

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