CodecMapper 0.3.0
Prefix Reserveddotnet add package CodecMapper --version 0.3.0
NuGet\Install-Package CodecMapper -Version 0.3.0
<PackageReference Include="CodecMapper" Version="0.3.0" />
<PackageVersion Include="CodecMapper" Version="0.3.0" />
<PackageReference Include="CodecMapper" />
paket add CodecMapper --version 0.3.0
#r "nuget: CodecMapper, 0.3.0"
#:package CodecMapper@0.3.0
#addin nuget:?package=CodecMapper&version=0.3.0
#tool nuget:?package=CodecMapper&version=0.3.0
CodecMapper
CodecMapper is a schema-first serialization library for F# with native AOT and Fable compatibility.
It lets you define one schema and compile it into multiple codecs. The same mapping drives both encode and decode, so JSON and XML stay symmetric.
It's for cases where the wire contract should be explicit, reviewable, and reusable instead of being inferred from CLR shape or serializer settings.
The idea
You author one Schema<'T> that describes the wire shape:
open CodecMapper
open CodecMapper.Schema
type Person = { Id: int; Name: string }
let makePerson id name = { Id = id; Name = name }
let personSchema =
define<Person>
|> construct makePerson
|> field "id" _.Id
|> field "name" _.Name
|> build
Then you compile that schema into a reusable codec:
let codec = Json.compile personSchema
let person = { Id = 1; Name = "Ada" }
let json = Json.serialize codec person
let decoded = Json.deserialize codec json
That is the core model of the library:
- the schema is the contract
- encode and decode come from the same definition
- contract changes stay visible in one place
That same authored path also covers explicit tagged unions, string-valued enums, message envelopes, and recursive case trees through Schema.union, Schema.inlineUnion, Schema.envelope, Schema.stringEnum, and Schema.delay.
Why use it
CodecMapper fits when:
- you want the wire contract to be authored explicitly
- JSON and XML should stay symmetric
- domain refinement should be explicit with
Schema.maporSchema.tryMap - Native AOT and Fable compatibility matter
It is not trying to replace convention-based serializers for every use case.
Formats and scope
The same authored schema can compile into:
- JSON codecs
- XML codecs
- config-oriented YAML codecs
- flat KeyValue projections
Authored tagged unions stay on that same contract path instead of switching to a separate codegen or reflection model.
The core library stays focused on explicit schemas and handwritten runtimes. The separate bridge assembly exists for .NET interoperability with existing C# serializer contracts.
Start here
- Introduction
- Getting Started
- How To Model A Basic Record
- How To Model A Nested Record
- How To Model A Validated Wrapper
- How To Model A Recursive Tagged Union
Use these after the core authored path is clear:
- How To Import Existing C# Contracts
- How To Export JSON Schema
- Tagged Union Wire Shape Reference
- JSON Schema in CodecMapper
- API Reference
Compatibility
CodecMapper is designed to stay usable from Native AOT and Fable-oriented targets. CI includes both in-repo compatibility sentinels and packaged-consumer Fable checks.
Performance Status
Current status is mixed but clear:
CodecMapperis competitive on small messages and medium nested-record workloads.System.Text.Jsonstill leads on string-heavy and numeric-heavy payloads.Newtonsoft.Jsontrails both across the current manual scenario matrix.
The project ships both a manual scenario runner and a repeatable perf workflow for hot-path investigation:
- manual runner:
dotnet run -c Release --project benchmarks/CodecMapper.Benchmarks.Runner/CodecMapper.Benchmarks.Runner.fsproj - profiling guide: docs/HOW_TO_PROFILE_BENCHMARK_HOT_PATHS.md
- full benchmark page: docs/BENCHMARKS.md
Latest local manual snapshot, measured on March 16, 2026:
| Scenario | CodecMapper serialize | STJ serialize | CodecMapper deserialize | STJ deserialize | Takeaway |
|---|---|---|---|---|---|
small-message |
519.5 ns |
676.9 ns |
990.1 ns |
928.4 ns |
CodecMapper still wins tiny-message serialize; STJ keeps a slight decode lead. |
person-batch-25 |
8.83 us |
8.36 us |
26.08 us |
20.41 us |
Medium nested serialize stays close, but decode is not yet even. |
person-batch-250 |
86.93 us |
78.18 us |
247.16 us |
190.27 us |
Larger nested batches remain competitive on serialize, while STJ leads decode throughput. |
escaped-articles-20 |
46.00 us |
33.87 us |
80.78 us |
63.08 us |
String-heavy payloads are still a clear weak spot. |
telemetry-500 |
393.93 us |
311.45 us |
745.63 us |
520.84 us |
Numeric-heavy flat payloads still need significant optimization work, especially on decode. |
person-batch-25-unknown-fields |
7.92 us |
7.51 us |
30.50 us |
24.23 us |
Unknown-field decode improved, but STJ still holds a noticeable lead. |
Those numbers are machine-specific. Compare ratios and workload shape more than the absolute values.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- FSharp.Core (>= 10.1.201)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
Added authored tagged unions and recursive unions across JSON, XML, YAML, and KeyValue; JSON Schema export for tagged unions and string enums; inline union, string enum, and message envelope helpers; refreshed docs, compatibility coverage, and benchmark snapshots.