gocsv
Struct-tag-based CSV marshaling and unmarshaling for Go, modeled after encoding/json.
Repository Health
Technical Analysis
GoCSV brings the ergonomics of Go’s encoding/json package to CSV files: annotate struct fields with csv:"..." tags and the library handles reading rows into structs and writing structs back out as CSV, including nested/embedded structs, custom type converters, and header normalization. It wraps the standard library’s encoding/csv reader and writer rather than replacing them, so callers can plug in a custom delimiter, quoting behavior, or error-handling strategy while still getting reflection-driven struct binding on top.
Beyond simple file-to-struct binding, gocsv exposes streaming entry points (UnmarshalToChan, UnmarshalToCallback) for processing large CSV files row-by-row without loading the whole file into memory, plus a two-column CSVToMap helper for the common case of turning a CSV into a Go map. It’s a dependency-free, single-purpose library aimed at Go services and CLIs that need to import or export tabular data without hand-writing per-field encoding/csv boilerplate.
What You Get
- Struct-tag-driven Marshal/Unmarshal functions for files, strings, byte slices, and io.Reader/io.Writer
- Nested and embedded struct support, with dotted
csv:"."tags to inline fields without column-name prefixing - Pluggable CSV reader/writer via SetCSVReader/SetCSVWriter for custom delimiters, quoting, and lazy-quote parsing
- Streaming decode helpers (UnmarshalToChan, UnmarshalToCallback, UnmarshalToCallbackWithError) for large files
- Custom per-type converters via the TypeMarshaller/TypeUnmarshaller interfaces and encoding.TextMarshaler support
- Header normalization hooks (SetHeaderNormalizer) for case-insensitive or fuzzy struct/CSV header matching
Common Use Cases
- Importing CSV exports (billing data, user lists, inventory feeds) directly into typed Go structs
- Exporting query results or report data from a Go service as downloadable CSV files
- Streaming very large CSV files into a channel or callback to avoid loading them fully into memory
- Building CLI tools that read/write CSV as a data interchange format between systems
- Converting simple two-column CSV files into Go maps for lookup tables or config data
Under The Hood
Architecture
The package is organized as a single flat gocsv package split by concern: csv.go exposes the public Marshal*/Unmarshal* API surface as thin wrappers, decode.go defines the Decoder/SimpleDecoder/CSVReader interfaces plus header-mismatch validation (mismatchStructFields, mismatchHeaderFields), reflect.go builds and caches per-type fieldInfo/structInfo via reflection in a sync.Map so struct introspection happens once per type, types.go defines the TypeMarshaller/TypeUnmarshaller conversion interfaces bridging Go values and CSV strings, and safe_csv.go wraps encoding/csv.Writer to surface write errors safely. Every marshal/unmarshal call path funnels through the shared structInfoCache, so callers that change the header normalizer (SetHeaderNormalizer) trigger an explicit cache reset — a central point that all encode/decode operations depend on.
Tech Stack
gocsv has zero third-party dependencies — go.mod declares only the module path and a Go 1.13 minimum, with everything built on encoding/csv (wrapped as CSVReader/SafeCSVWriter), reflect for struct introspection, encoding.TextMarshaler for interop with the standard marshaling interfaces, and sync/sync.Map for concurrent-safe caching. It’s a self-contained importable package with no runtime, database, or network dependencies, installed via go get.
Code Quality
Seven dedicated test files (csv_test.go, decode_test.go, encode_test.go, reflect_test.go, types_test.go, unmarshaller_test.go, custom_unmarshaller_test.go) give extensive coverage of the public API and internal helpers using Go’s standard testing package. Errors are explicit and typed rather than swallowed — sentinel errors (ErrUnmatchedStructTags, ErrDoubleHeaderNames, ErrEmptyCSVFile, ErrNoStructTags) are wrapped with %w, and dedicated NoMarshalFuncError/NoUnmarshalFuncError types carry descriptive messages. Naming follows idiomatic Go conventions, and both a legacy Travis config and a modern GitHub Actions workflow run CI, though no linter configuration is present in the repo.
What Makes It Unique gocsv doesn’t introduce a new parsing model — it applies the well-established encoding/json struct-tag pattern (explicitly credited to gopkg.in/mgo.v2’s techniques) to CSV. Its practical differentiators are a pluggable reader/writer for custom delimiters and lazy quoting, a header normalizer hook for fuzzy/case-insensitive column matching, zero-width-character stripping for real-world messy CSV headers, dotted-tag struct inlining, and a comprehensive set of channel- and callback-based streaming unmarshal variants for processing large files without loading them fully into memory.
Used by 2 apps in this directory
Rill
Analytics · Data Engineering
The fastest BI tool for humans and agents — define metrics, models, and dashboards as code and query them instantly on ClickHouse or DuckDB.
Vikunja
Project Management
Self-hosted task management with natural-language quick-add, multiple views, and a fully documented REST API — your tasks, your infrastructure, zero lock-in.