Problem
The current serialization APIs (Result.serialize / Result.deserialize) are too inflexible for 3.0. They only preserve the outer Result shape and assume the inner ok / err payloads are already wire-safe and can be trusted on the way back in.
That makes common boundary use cases awkward:
- mapping domain objects/errors into explicit wire schemas
- validating unknown input while deserializing
- using different schemas for outbound vs inbound payloads
- colocating serde behavior with a reusable
Result-level codec
Proposed direction
Introduce a codec-style API that accepts per-variant serializers/deserializers and returns an object with serialize / deserialize helpers.

Sketch:
import { Result } from "better-result";
const UserResultCodec = Result.codec({
serialize: {
ok: UserToWireSchema,
err: AppErrorToWireSchema,
},
deserialize: {
ok: WireToUserSchema,
err: WireToAppErrorSchema,
},
});
// sending network boundary
UserResultCodec.serialize(result);
// receiving network boundary
UserResultCodec.deserialize(input);
Open questions
- What schema/codec interface should
Result.codec accept? (Standard Schema, custom parse/encode contract, adapters, etc.)
- Should
deserialize return Result<Result<T, E>, ResultDeserializationError> or keep the current flattened Result<T, E | ResultDeserializationError> style?
- Should the legacy
Result.serialize / Result.deserialize stay as simple defaults, become wrappers over Result.codec, or be removed/reworked in 3.0?
- How should errors from ok/err payload decoding be represented and typed?
Acceptance criteria
- Design a flexible serde API for 3.0 centered around
Result.codec or equivalent.
- Preserve strong inference for both ok and err payloads in serialize and deserialize directions.
- Support safe deserialization from
unknown at network/process boundaries.
- Document migration guidance from the current
Result.serialize / Result.deserialize APIs.
Problem
The current serialization APIs (
Result.serialize/Result.deserialize) are too inflexible for 3.0. They only preserve the outerResultshape and assume the innerok/errpayloads are already wire-safe and can be trusted on the way back in.That makes common boundary use cases awkward:
Result-level codecProposed direction
Introduce a codec-style API that accepts per-variant serializers/deserializers and returns an object with
serialize/deserializehelpers.Sketch:
Open questions
Result.codecaccept? (Standard Schema, custom parse/encode contract, adapters, etc.)deserializereturnResult<Result<T, E>, ResultDeserializationError>or keep the current flattenedResult<T, E | ResultDeserializationError>style?Result.serialize/Result.deserializestay as simple defaults, become wrappers overResult.codec, or be removed/reworked in 3.0?Acceptance criteria
Result.codecor equivalent.unknownat network/process boundaries.Result.serialize/Result.deserializeAPIs.