title: Native Serialization sidebar_position: 3 id: native_serialization license: | Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the “License”); you may not use this file except in compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Go native serialization is the Go-only wire mode selected with fory.WithXlang(false). Use it when every writer and reader is a Go service and the payload should follow Go's type system instead of the portable xlang type system.
Use Xlang Serialization, the default Go mode, when bytes must be read by Java, Python, C++, Rust, JavaScript/TypeScript, C#, Swift, Dart, Scala, Kotlin, or another non-Go Fory implementation.
Use native serialization when:
int/uint, nil slices, nil maps, pointers, interfaces, or Go-only dynamic values.package main
import "github.com/apache/fory/go/fory"
type Order struct {
ID int64
Amount float64
}
func main() {
f := fory.New(fory.WithXlang(false))
if err := f.RegisterStruct(Order{}, 100); err != nil {
panic(err)
}
data, err := f.Serialize(&Order{ID: 1, Amount: 42.5})
if err != nil {
panic(err)
}
var decoded Order
if err := f.Deserialize(data, &decoded); err != nil {
panic(err)
}
}
Reuse a configured Fory instance. The default instance owns reusable buffers and is not thread-safe; use the thread-safe wrapper for concurrent goroutines.
import (
"github.com/apache/fory/go/fory"
"github.com/apache/fory/go/fory/threadsafe"
)
f := threadsafe.New(fory.WithXlang(false), fory.WithTrackRef(true))
_ = f.RegisterStruct(Order{}, 100)
Native serialization defaults to compatible mode. Keep that default when Go-only services roll independently:
writer := fory.New(fory.WithXlang(false))
reader := fory.New(fory.WithXlang(false))
Compatible mode writes schema metadata so readers can tolerate added, removed, or reordered fields when field names or explicit field IDs remain compatible. See Schema Evolution.
For faster serialization and smaller size, set WithCompatible(false) only when every reader and writer always uses the same Go struct schema.
Register structs before serializing them. Prefer explicit numeric IDs for long-lived payloads:
_ = f.RegisterStruct(Order{}, 100)
_ = f.RegisterStruct(LineItem{}, 101)
Name-based registration is useful when ID coordination is harder:
_ = f.RegisterStructByName(Order{}, "example.Order")
If you register without stable IDs, every writer and reader must make the same registration choices.
Native serialization keeps Go data in Go-native form:
int and uint.time.Time and time.Duration.Use Supported Types for the full type surface and xlang mapping details.
Enable reference tracking for shared object identity or cycles:
f := fory.New(fory.WithXlang(false), fory.WithTrackRef(true))
type Node struct {
Value int32
Next *Node `fory:"ref"`
}
Disable reference tracking for value-shaped data. It is faster and smaller, but repeated pointers deserialize as independent values and cyclic graphs are unsupported.
The default Fory instance reuses its internal buffer. Copy serialized bytes if they must outlive the next serialization call:
data, _ := f.Serialize(value)
stable := append([]byte(nil), data...)
The thread-safe wrapper copies bytes before returning them. For high-throughput single-threaded code, serialize into a caller-owned ByteBuffer:
buf := fory.NewByteBuffer(nil)
err := f.SerializeTo(buf, value)
data := buf.GetByteSlice(0, buf.WriterIndex())
_ = err
_ = data
Fory or the thread-safe wrapper instead of constructing a Fory instance per request.WithCompatible(false) only when every reader and writer always uses the same Go struct schema and wants faster serialization and smaller size.| Requirement | Use native serialization | Use xlang serialization |
|---|---|---|
| Go-only payloads | Yes | Optional |
| Non-Go readers or writers | No | Yes |
Go-native int, uint, nil slice/map | Yes | Limited |
| Same-schema compact payloads | Yes | No |
| Compatible schema evolution by default | Yes | Yes |
| Portable type mapping across languages | No | Yes |
The writer is using native serialization. Rebuild it with fory.WithXlang(true) and align type registration with every peer.
Native serialization defaults to compatible mode. Keep that default when struct definitions can differ.
Use native serialization for Go-only payloads that must preserve Go nil slice/map semantics. Cross-language schemas should model nullability explicitly.
The default Fory instance reuses its buffer. Copy the byte slice or use threadsafe.New(...).