wireform-flatbuffers
wireform-flatbuffers implements Google FlatBuffers,
a zero-copy serialization format designed for game engines, mobile apps, and
real-time inference serving. FlatBuffers lay out tables with vtables that index
field offsets, keeping scalars inline and strings or sub-tables behind indirection.
Use this package when you need to read large buffers without deserializing the
entire message, or when sharing the builder infrastructure with Arrow IPC.
Key features
Section titled “Key features”- Typeclass API via
ToFlatBuffersandFromFlatBufferswith Template Haskell deriving - FlatBuffers IDL parser and codegen from
.fbsschema files - Vtable-based wire layout with inline scalars and offset-indirected collections
- Zero-copy view/reader via
FlatBuffers.Viewfor schema-known access patterns - Shared builder with Arrow IPC for cross-format buffer construction
- QuasiQuoter for inline
[flatbuffers| ... |]schemas
Basic usage
Section titled “Basic usage”Derive instances for your table types, then encode and decode through the value-level codec:
{-# LANGUAGE DerivingStrategies #-}{-# LANGUAGE TemplateHaskell #-}
import FlatBuffers.Decode qualified as FBDimport FlatBuffers.Derive (ToFlatBuffers (..), FromFlatBuffers (..), deriveFlatBuffers, deriveView)import FlatBuffers.Encode qualified as FBEimport Data.Int (Int32)import Data.Text (Text)import GHC.Generics (Generic)
data Widget = Widget { widgetName :: !Text , widgetCount :: !Int32 , widgetPrice :: !Double } deriving stock (Show, Eq, Generic)
$(deriveFlatBuffers ''Widget)$(deriveView ''Widget)
encodeWidget :: Widget -> ByteStringencodeWidget = FBE.encode . toFlatBuffers
decodeWidget :: ByteString -> Either String WidgetdecodeWidget bs = do val <- FBD.decode bs fromFlatBuffers val
sample :: Widgetsample = Widget "wireform" 42 2.718
roundTrip :: Either String WidgetroundTrip = decodeWidget (encodeWidget sample)For zero-copy reads on known schemas, use the view layer after encoding:
import FlatBuffers.View (decodeRoot)
readWidget :: ByteString -> Either String WidgetreadWidget = decodeRootGenerate types from .fbs files:
{-# LANGUAGE TemplateHaskell #-}import FlatBuffers.QQ (fbs)
[fbs| table Widget { name:string; count:int; price:double; } root_type Widget;|]wireform-gen flatbuffers -i schema.fbs -o src/Gen/Performance
Section titled “Performance”Encode/decode (zero-copy decode)
Section titled “Encode/decode (zero-copy decode)”| Operation | encode | decode | ratio |
|---|---|---|---|
| Person table | 827 ns | 142 ns | 0.17x |
| Person[100] vector | 95352 ns | 75.7 ns | 0.00x |
Last run 2026-06-27 11:35:54 UTC. ghc-9.8.4 on darwin-aarch64, criterion 1.6.5. Decode is a zero-copy cursor by design: only the outer envelope is resolved at decode time. Per-field reads happen lazily..
Like Cap’n Proto, FlatBuffers decode is a zero-copy cursor. The decode cost is near-constant because only the root table offset is resolved; field access is lazy pointer arithmetic into the original buffer. Encode is proportional to the number of fields and vector elements.
The chart and table above are regenerated by wireform-stats from wireform-flatbuffers/bench-results/summary/flatbuffers-encode-decode.json — the same source the README chart is built from.
Notable modules
Section titled “Notable modules”| Module | Purpose |
|---|---|
FlatBuffers.Derive | ToFlatBuffers / FromFlatBuffers and deriveFlatBuffers |
FlatBuffers.Encode / FlatBuffers.Decode | High-level encoder and value-tree decoder |
FlatBuffers.View | Zero-copy cursor access for schema-known tables |
FlatBuffers.Reader | Low-level pointer-walking decoder |
FlatBuffers.Builder | Vtable and offset builder |
FlatBuffers.Value | Dynamic untyped Value ADT |
FlatBuffers.Schema / FlatBuffers.Parser | Schema AST and .fbs parser |
FlatBuffers.CodeGen / FlatBuffers.QQ | Haskell codegen and quasiquoter |
FlatBuffers.Registry | Runtime schema registry |