Protocols
Katman supports three wire formats — JSON, MessagePack, and devalue — plus WebSocket for persistent connections.
When a client sends a request, the server needs to agree on how to encode the data. Katman handles this automatically through content negotiation — the client says what format it wants via the Accept header, and the server responds accordingly. No configuration needed.
The three formats
| Format | Payload size | Rich types | Binary | Best for |
|---|---|---|---|---|
| JSON | Baseline | No | No | Default, universal compatibility |
| MessagePack | ~30% smaller | Date, Set, Map | Yes | Mobile apps, bandwidth-sensitive |
| devalue | ~Same as JSON | Date, Map, Set, BigInt, RegExp, circular refs | No | APIs returning rich JavaScript types |
JSON is the default. Every client and every tool understands it. If you don't configure anything, this is what you get.
MessagePack is a binary format. Same data, fewer bytes. If you're building a mobile app or sending large payloads, switching to MessagePack can noticeably reduce bandwidth and improve parse speed.
devalue preserves JavaScript types that JSON loses. If your API returns Date objects, Map, Set, or BigInt, devalue keeps them intact instead of converting them to strings or empty objects.
How content negotiation works
The client sends an Accept header, and the server picks the matching format:
Accept: application/json --> JSON (default)
Accept: application/x-msgpack --> MessagePack
Accept: application/x-devalue+json --> devalueFor request bodies, the server checks Content-Type and decodes accordingly. This all happens inside Katman — you don't need to configure anything on the server.
On the client side, setting binary: true in createLink switches to MessagePack automatically:
import { } from "katman/client/ofetch"
const = ({
: "http://localhost:3000",
: true, // uses MessagePack for all requests
})You can also use these formats over WebSocket. Pass binary: true to attachWebSocket for MessagePack over WebSocket.
Choose a format
Most applications work great with plain JSON. Consider switching when:
- You need smaller payloads (mobile, IoT, high-traffic) --> MessagePack
- Your API returns Date, Map, Set, or BigInt --> devalue
- You want the lowest possible latency for repeated calls --> WebSocket