Repository navigation
v2.10 speeds up encoding by up to 2.88× and decoding by up to 1.87× with zero memory regressions (B/op, allocs/op), reduces memory use, adds the toindefarray struct tag option, and fixes bugs. The Contributing Guidelines, Security Policy, and templates were extensively updated.
Encoding sorted nested maps of dynamic JSON-like data to CBOR drops from 70 allocs/op to 1 and from 7.2 KiB/op to 4.0 KiB/op in the benchmarks below. Encoding time.Time, big.Int, Tag and Marshaler values, and decoding into time.Time, big.Int and Tag, use 1 to 2 fewer allocs/op (20% to 50% fewer).
This release does not use Go's unsafe package. Performance in user apps depends on configuration and data.
Tests were refactored and coverage increased to 97.7%. Fuzz tests (not yet public) were also extended. Internal checklists and procedures were updated to reduce potential mistakes.
Performance and Benchmarks
Across all 215 benchmarks, there are zero memory regressions (B/op, allocs/op). Just one benchmark showed a speed dip: Marshal/struct_many_flds_all_omitempty_all_empty/map is ~4-5% slower, but only when a struct has 32 fields that are both omitzero and empty (same scenario with an 8-field struct is now faster).
Benchmarks ran with Go 1.26.10 on linux/amd64 (benchstat n=10, p=0.000):
- CBOR Speedup by Data Type: groups of different benchmarks summarized per row
- CBOR Encoding Reflection-Free Speedup: dynamic JSON-like data types and common types
CBOR Speedup by Data Type
| Unmarshal | Speedup | ΔSec/op |
|---|---|---|
| Single values (bool, int, float, byte string, text string) | 1.10× to 1.51×¹ | -8.87% to -33.92%¹ |
| Epoch time, bignum, other tags | 1.18× to 1.64× | -15.33% to -38.91% |
| Arrays and maps to non-struct | 1.33× to 1.87× | -24.63% to -46.49% |
| Arrays and maps to structs | 1.06× to 1.52× | -5.46% to -34.40% |
| Real-world (COSE, CWT, SenML, WebAuthn) | 1.35× to 1.64× | -26.06% to -39.19% |
¹ 2.54× speedup (-60.64%) when decoding into a named []byte type that has methods.
| Marshal | Speedup | ΔSec/op |
|---|---|---|
| Single values (bool, int, float, byte slice, string) | 1.32× to 1.55× | -24.49% to -35.41% |
| time.Time, big.Int, Tag, Marshaler² | 1.15× to 1.63× | -12.94% to -38.84% |
| Slices and maps | 1.35× to 2.88× | -25.97% to -65.26% |
| Structs | 1.57× to 2.17× | -36.37% to -53.96% |
| Structs with omitempty fields | 0.95׳ to 1.35× | +5.01%³ to -25.96% |
| Real-world (COSE, CWT, SenML, WebAuthn) | 1.12× to 1.33× | -10.66% to -24.77% |
² For addressable values (reached through a pointer, struct field, slice element or map value).
³ Only when every field is omitempty and empty: 7.6 ns slower for a 32-field struct, 2.37 ns faster for an 8-field struct. This is the only performance regression in all 215 benchmarks.
CBOR Encoding Reflection-Free Speedup
PR #870 optimized common types: int, int64, uint, uint64, float64, bool, string, nil, []byte, []any, map[any]any, map[string]any, and map[string]string.
| Marshal Benchmark v2.9.6 → v2.10 |
Speedup | Time ΔSec/op |
Memory ΔB/op |
Memory ΔAllocs/op |
|---|---|---|---|---|
| []any | 2.50× | -607.5 ns (-60.03%) | - | - |
| map[string]any | 2.60× | -821.9 ns (-61.47%) | - | - |
| map[string]string | 2.59× | -335.9 ns (-61.34%) | - | - |
| nested_map[any]any | 2.88× | -16.542 µs (-65.26%) | - | - |
| nested_map[string]any | 2.78× | -14.201 µs (-64.01%) | - | - |
| nested_map[any]any, bw_lex | 2.53× | -22.36 µs (-60.54%) | -3314 (-44.72%) | -69 (-98.57%) |
| nested_map[string]any, bw_lex | 2.41× | -19.52 µs (-58.54%) | -3323 (-44.79%) | -69 (-98.57%) |
Upgrade Notes
- Go 1.24 or newer is required (#773). All tests (97.7% coverage) pass on Go 1.24-1.27.
- Pointer-receiver marshal methods (user-implemented methods) are called on the original value instead of a copy when the value is addressable (#866).
Marshalconfigured to useTagsForbiddenreturns an error for abig.Intoutside [-2^64, 2^64-1], andEncModecreation returns an error for settings that would emit tags ifTagsForbiddenis also set (#868).Decoderadvances past well-formed data items rejected byDecOptionsvalue or serialization restrictions (e.g.NaN,IndefLength), andSkipskips them without an error (#872).Marshalconfigured to emit text-based time returns an error fortime.Timeoutside RFC 3339 limits (#873).
TinyGo (experimental)
TinyGo support for v2.10.0 is available in tag tinygo-beta/v2.10.0-tinygo0.42 (branch feature/cbor-tinygo-beta). It requires TinyGo 0.42.0 or newer. It is experimental and not fuzz tested. For details, see TinyGo (https://github.com/fxamacker/cbor#tinygo) in the README.
What's Changed
⭐ Features
- feat: add toindefarray struct tag option for CBOR indefinite-length arrays by @tdnguyenND in #770
🚀 Optimizations
- Optimize encoding speed primarily for slices, maps, and structs by @fxamacker in #806
- Reduce decoding time up to 17% for all CBOR data types by @fxamacker in #807
- Reduce decoding time by inlining well-formedness checks by @fxamacker in #810
- Optimize decoding CBOR byte string by @fxamacker in #811
- Optimize decoding CBOR text string by up to 16% by @fxamacker in #812
- Reduce allocs and bound memory of keyValue pool by @fxamacker in #860
- Reduce allocations when encoding addressable values by @fxamacker in #866
- Add reflection-free encoding for common types (up to 2.8x faster) by @fxamacker in #870
- Reduce allocs to speed up time.Time, Tag, and big.Int by @fxamacker in #886
🛠 Improvements
- Update to require go 1.24 and modernize code by @fxamacker in #773
- Refactor to use slices.SortFunc (Go 1.21+) by @fxamacker in #774
- Small refactor and cleanups by @fxamacker in #815
- Refactor encoding functions to prepare for reflection-free path by @fxamacker in #861
- Refactor struct field sorter to use slices.SortFunc by @fxamacker in #877
🐞 Bug Fixes
- Enforce TagsForbidden for bignums and ByteSliceLaterFormat by @fxamacker in #868
- Advance Decoder past restricted CBOR data items by @fxamacker in #872
- Reject marshaling out-of-range time.Time to RFC 3339 by @fxamacker in #873
- Fix some error messages returned by EncMode() and DecMode() by @fxamacker in #883
- Fix float range check when decoding Unix time by @fxamacker in #889
🧪 Testing
- Shorten benchmark names by @fxamacker in #816
- Move tests and helpers to new files by @fxamacker in #878
- Add checkMarshal test helpers by @fxamacker in #879
- Add checkUnmarshal test helpers by @fxamacker in #881
- Add test helpers for modes, tags, and round trips by @fxamacker in #884
- Refactor invalid option tests to table-driven tests by @fxamacker in #885
- Add checkNoError and checkErrorCase test helpers by @fxamacker in #887
- Standardize test failure messages and fix several test bugs by @fxamacker in #888
- Add more benchmarks by @fxamacker in #891
📖 Documentation
- Update comments to use newer terminology by @fxamacker in #779
- Update TinyGo section in README.md by @fxamacker in #793
- Update doc.go and README.md for v2.10.0 by @fxamacker in #890
📖 Contributing Guidelines, Security Policy, and Templates
- Update PR template to clarify approval requirement by @fxamacker in #849
- Rewrite security policy and reporting guidelines by @fxamacker in #864
- Rewrite PR template to reduce risks from AI and uncoordinated PRs by @fxamacker in #865
- Rewrite bug report form to reduce security risks by @fxamacker in #867
- Rewrite feature request form to help triage and reduce risks by @fxamacker in #869
- Replace docs issue template with an issue form by @fxamacker in #874
- Update security policy, PR template, and issue forms by @fxamacker in #875
- Update CONTRIBUTING.md to reduce risks by @fxamacker in #862
- Improve issue forms for triage and previews by @fxamacker in #880
CI / GitHub Actions
🔎 Details
- Bump govulncheck from v1.1.4 to v1.3.0 by @fxamacker in #772
- Add more linters to .golangci.yml and lint by @fxamacker in #775
- Update CodeQL actions to v4.36.3 and add CodeQL group to dependabot.yml by @fxamacker in #790
- Bump golangci-lint to v2.13.2 and lint by @fxamacker in #814
- Update CI to add Go 1.27 and bump govulncheck by @fxamacker in #852
- Change Go version for golangci-lint 2.13.2 by @fxamacker in #863
Other Changes
- Use a security-hardened .gitignore by @fxamacker in #826
Ported from release-2.9
Already released in v2.9.3 through v2.9.6.
🔎 Details
- Port PR 803 to master branch by @fxamacker in #804
- Port #817 from v2.9.4 to master by @fxamacker in #818
- Port #821 from release-2.9 to master by @fxamacker in #822
- Port #827 from release-2.9 to master by @fxamacker in #839
- Port #828 from release-2.9 to master by @fxamacker in #840
- Port #829 from release-2.9 to master by @fxamacker in #841
- Port #831 from release-2.9 to master by @fxamacker in #842
- Port #834 from release-2.9 to master by @fxamacker in #843
- Port #835 from release-2.9 to master by @fxamacker in #844
- Port #833 from release-2.9 to master by @fxamacker in #845
- Port #837 from release-2.9 to master by @fxamacker in #846
- Port #838 from release-2.9 to master by @fxamacker in #850
- Port #851 from release-2.9 to master by @fxamacker in #853
- Port #854 from release-2.9 to master by @fxamacker in #856
- Port #857 from release-2.9 to master by @fxamacker in #858
- Port #855 from v2.9.6 to master by @fxamacker in #859
Dependabot Updates
🔎 Details
- Bump github/codeql-action from 4.35.2 to 4.35.4 by @dependabot[bot] in #771
- Bump github/codeql-action from 4.35.4 to 4.35.5 by @dependabot[bot] in #776
- Bump github/codeql-action from 4.35.5 to 4.36.0 by @dependabot[bot] in #778
- Bump github/codeql-action from 4.36.0 to 4.36.2 by @dependabot[bot] in #781
- Bump actions/checkout from 6.0.2 to 7.0.0 by @dependabot[bot] in #783
- Bump actions/setup-go from 6.4.0 to 6.5.0 by @dependabot[bot] in #785
- Bump the codeql group with 3 updates by @dependabot[bot] in #791
- Bump the codeql group with 3 updates by @dependabot[bot] in #794
- Bump actions/setup-go from 6.5.0 to 7.0.0 by @dependabot[bot] in #795
- Bump the codeql group with 3 updates by @dependabot[bot] in #799
- Bump actions/checkout from 7.0.0 to 7.0.1 by @dependabot[bot] in #800
- Bump the codeql group with 3 updates by @dependabot[bot] in #801
- Bump the codeql group with 3 updates by @dependabot[bot] in #808
- Bump the codeql group across 1 directory with 3 updates by @dependabot[bot] in #813
- Bump the codeql group with 3 updates by @dependabot[bot] in #823
- Bump the codeql group with 3 updates by @dependabot[bot] in #836
- Bump the codeql group with 3 updates by @dependabot[bot] in #847
- Bump the codeql group with 3 updates by @dependabot[bot] in #871
- Bump the codeql group with 3 updates by @dependabot[bot] in #882
New Contributors
- @tdnguyenND made their first contribution in #770
Full Changelog: v2.9.6...v2.10.0