Documentation Index
Fetch the complete documentation index at: https://docs.goakt.dev/llms.txt
Use this file to discover all available pages before exploring further.
Overview
Messages crossing process boundaries must be serialized. GoAkt v4 ships three pluggable serializers and supports custom implementations via theSerializer interface.
| Serializer | Wire format | Best for |
|---|---|---|
| ProtoSerializer | protobuf (default) | proto.Message types — schema-driven, compact, language-portable. |
| CBORSerializer | CBOR (binary) | Plain Go structs — compact binary, faster than JSON, schema-less. |
| JSONSerializer | JSON (via sonic) | Plain Go structs where interoperability or human-readability is wanted. |
ProtoSerializer (default)
Protobuf messages use the default serializer automatically. No registration needed forproto.Message types — NewConfig registers ProtoSerializer for the proto.Message interface, and proto’s own protoregistry.GlobalTypes (populated by generated init() functions) resolves the concrete type on the receiver.
CBOR for plain Go structs
For plain Go structs, useremote.WithSerializers(new(MyMessage), remote.NewCBORSerializer()) when creating the remote
config. Types are registered automatically in the type registry. Both sender and receiver must register the same types
via WithSerializers; for receive-only types, register them the same way — the type is auto-registered for
deserialization.
For bulk registration, remote.WithSerializables(new(MyMessage), new(OtherMessage)) registers each type with a shared CBOR serializer instance.
JSON for plain Go structs
JSON works identically to CBOR — same registration path, same wire frame, different encoding.JSONSerializer is backed by bytedance/sonic configured for maximum throughput (sonic.ConfigFastest — no HTML escaping, no JSON-marshaler validation). On amd64 and arm64 sonic uses JIT-accelerated fast paths; on other architectures it transparently falls back to encoding/json.
CBOR vs JSON
Pick CBOR when both ends are goAkt and you want the smallest payloads and fastest decode. Pick JSON when payloads need to be human-readable in logs, inspected withjq, or consumed by non-goAkt tooling. Both share the same registry plumbing — switching is a one-line change in your config.
How Go types are magically serialized
When you pass a concrete Go type toWithSerializers with CBORSerializer or JSONSerializer, the type is automatically registered
in a global type registry. There is no separate registration step — no RegisterSerializableTypes or similar.
One line does it all:
-
On config build: When
WithSerializers(new(MyMessage), serializer)is applied, GoAkt detects that the serializer uses the registry (CBOR or JSON) and the type is a concrete non-proto struct. It registersMyMessagein a global type registry keyed by the type’s reflected name. - On serialize: When a message is sent, the serializer looks up the type name in the registry, encodes the value as CBOR or JSON, and prepends a self-describing frame (total length, type name length, type name, payload). The receiver can reconstruct the exact Go type from the type name.
- On deserialize: When bytes arrive, the frame header is parsed, the type name is extracted, and the registry is consulted to resolve the concrete Go type. A new instance is allocated and the payload is unmarshaled into it.
WithSerializers. For types you only receive (never send),
register them the same way — the type is auto-registered for deserialization. Proto message types are excluded from
this registry; they use protobuf’s own type resolution.
The Serializer interface
Custom serializers must implement:| Method | Purpose |
|---|---|
| Serialize | Encode a message into bytes. The encoding must be self-describing so the receiver can reconstruct the concrete type without out-of-band coordination. |
| Deserialize | Decode bytes back into the original Go value. The dynamic type must match what was passed to Serialize. |
WithSerializers(msgType, serializer) on the remote
config.