This is an automated email from the ASF dual-hosted git repository.
chaokunyang pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/fory-site.git
The following commit(s) were added to refs/heads/main by this push:
new 5366c454f 🔄 synced local 'docs/docs/guide/' with remote 'docs/guide/'
5366c454f is described below
commit 5366c454f0e8f9e291f9c54dda92d8c3132eb88b
Author: chaokunyang <[email protected]>
AuthorDate: Mon Jan 12 03:48:32 2026 +0000
🔄 synced local 'docs/docs/guide/' with remote 'docs/guide/'
---
docs/docs/guide/go/basic-serialization.md | 404 +++++++++++++++++++
docs/docs/guide/go/codegen.md | 420 ++++++++++++++++++++
docs/docs/guide/go/configuration.md | 344 +++++++++++++++++
docs/docs/guide/go/cross-language.md | 282 ++++++++++++++
docs/docs/guide/go/custom-serializers.md | 285 ++++++++++++++
docs/docs/guide/go/index.md | 162 ++++++++
docs/docs/guide/go/references.md | 356 +++++++++++++++++
docs/docs/guide/go/schema-evolution.md | 340 ++++++++++++++++
docs/docs/guide/go/struct-tags.md | 335 ++++++++++++++++
docs/docs/guide/go/supported-types.md | 369 ++++++++++++++++++
docs/docs/guide/go/thread-safety.md | 347 +++++++++++++++++
docs/docs/guide/go/troubleshooting.md | 448 ++++++++++++++++++++++
docs/docs/guide/go/type-registration.md | 262 +++++++++++++
docs/docs/guide/xlang/field-reference-tracking.md | 22 +-
14 files changed, 4365 insertions(+), 11 deletions(-)
diff --git a/docs/docs/guide/go/basic-serialization.md
b/docs/docs/guide/go/basic-serialization.md
new file mode 100644
index 000000000..130e444eb
--- /dev/null
+++ b/docs/docs/guide/go/basic-serialization.md
@@ -0,0 +1,404 @@
+---
+title: Basic Serialization
+sidebar_position: 20
+id: go_basic_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
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+---
+
+This guide covers the core serialization APIs in Fory Go.
+
+## Creating a Fory Instance
+
+Create a Fory instance and register your types before serialization:
+
+```go
+import "github.com/apache/fory/go/fory"
+
+f := fory.New()
+
+// Register struct with a type ID
+f.RegisterStruct(User{}, 1)
+f.RegisterStruct(Order{}, 2)
+
+// Or register with a name (more flexible, less prone to ID conflicts, but
higher serialization cost)
+f.RegisterNamedStruct(User{}, "example.User")
+
+// Register enum types
+f.RegisterEnum(Color(0), 3)
+```
+
+**Important**: The Fory instance should be reused across serialization calls.
Creating a new instance involves allocating internal buffers, type caches, and
resolvers, which is expensive. The default Fory instance is not thread-safe;
for concurrent usage, use the thread-safe wrapper (see [Thread
Safety](thread-safety)).
+
+See [Type Registration](type-registration) for more details.
+
+## Core API
+
+### Serialize and Deserialize
+
+The primary API for serialization:
+
+```go
+// Serialize any value
+data, err := f.Serialize(value)
+if err != nil {
+ // Handle error
+}
+
+// Deserialize into target
+var result MyType
+err = f.Deserialize(data, &result)
+if err != nil {
+ // Handle error
+}
+```
+
+### Marshal and Unmarshal
+
+Aliases for `Serialize` and `Deserialize` (familiar to Go developers):
+
+```go
+data, err := f.Marshal(value)
+err = f.Unmarshal(data, &result)
+```
+
+## Serializing Primitives
+
+```go
+// Integers
+data, _ := f.Serialize(int64(42))
+var i int64
+f.Deserialize(data, &i) // i = 42
+
+// Floats
+data, _ = f.Serialize(float64(3.14))
+var fl float64
+f.Deserialize(data, &fl) // fl = 3.14
+
+// Strings
+data, _ = f.Serialize("hello")
+var s string
+f.Deserialize(data, &s) // s = "hello"
+
+// Booleans
+data, _ = f.Serialize(true)
+var b bool
+f.Deserialize(data, &b) // b = true
+```
+
+## Serializing Collections
+
+### Slices
+
+```go
+// String slice
+strs := []string{"a", "b", "c"}
+data, _ := f.Serialize(strs)
+
+var result []string
+f.Deserialize(data, &result)
+// result = ["a", "b", "c"]
+
+// Integer slice
+nums := []int64{1, 2, 3}
+data, _ = f.Serialize(nums)
+
+var intResult []int64
+f.Deserialize(data, &intResult)
+// intResult = [1, 2, 3]
+```
+
+### Maps
+
+```go
+// String to string map
+m := map[string]string{"key": "value"}
+data, _ := f.Serialize(m)
+
+var result map[string]string
+f.Deserialize(data, &result)
+// result = {"key": "value"}
+
+// String to int map
+m2 := map[string]int64{"count": 42}
+data, _ = f.Serialize(m2)
+
+var result2 map[string]int64
+f.Deserialize(data, &result2)
+// result2 = {"count": 42}
+```
+
+## Serializing Structs
+
+### Basic Struct Serialization
+
+Only **exported fields** (starting with uppercase) are serialized:
+
+```go
+type User struct {
+ ID int64 // Serialized
+ Name string // Serialized
+ password string // NOT serialized (unexported)
+}
+
+f.RegisterStruct(User{}, 1)
+
+user := &User{ID: 1, Name: "Alice", password: "secret"}
+data, _ := f.Serialize(user)
+
+var result User
+f.Deserialize(data, &result)
+// result.ID = 1, result.Name = "Alice", result.password = ""
+```
+
+### Nested Structs
+
+```go
+type Address struct {
+ City string
+ Country string
+}
+
+type Person struct {
+ Name string
+ Address Address
+}
+
+f.RegisterStruct(Address{}, 1)
+f.RegisterStruct(Person{}, 2)
+
+person := &Person{
+ Name: "Alice",
+ Address: Address{City: "NYC", Country: "USA"},
+}
+
+data, _ := f.Serialize(person)
+
+var result Person
+f.Deserialize(data, &result)
+// result.Address.City = "NYC"
+```
+
+### Pointer Fields
+
+```go
+type Node struct {
+ Value int32
+ Child *Node
+}
+
+// Use WithTrackRef for pointer fields
+f := fory.New(fory.WithTrackRef(true))
+f.RegisterStruct(Node{}, 1)
+
+root := &Node{
+ Value: 1,
+ Child: &Node{Value: 2, Child: nil},
+}
+
+data, _ := f.Serialize(root)
+
+var result Node
+f.Deserialize(data, &result)
+// result.Child.Value = 2
+```
+
+## Streaming API
+
+For scenarios where you want to control the buffer:
+
+### SerializeTo
+
+Serialize to an existing buffer:
+
+```go
+buf := fory.NewByteBuffer(nil)
+
+// Serialize multiple values to same buffer
+f.SerializeTo(buf, value1)
+f.SerializeTo(buf, value2)
+
+// Get all serialized data
+data := buf.GetByteSlice(0, buf.WriterIndex())
+```
+
+### DeserializeFrom
+
+Deserialize from an existing buffer:
+
+```go
+buf := fory.NewByteBuffer(data)
+
+var result1, result2 MyType
+f.DeserializeFrom(buf, &result1)
+f.DeserializeFrom(buf, &result2)
+```
+
+## Generic API (Type-Safe)
+
+Fory Go provides generic functions for type-safe serialization:
+
+```go
+import "github.com/apache/fory/go/fory"
+
+type User struct {
+ ID int64
+ Name string
+}
+
+// Type-safe serialization
+user := &User{ID: 1, Name: "Alice"}
+data, err := fory.Serialize(f, user)
+
+// Type-safe deserialization
+var result User
+err = fory.Deserialize(f, data, &result)
+```
+
+The generic API:
+
+- Infers type at compile time
+- Provides better type safety
+- May offer performance benefits
+
+## Error Handling
+
+Always check errors from serialization operations:
+
+```go
+data, err := f.Serialize(value)
+if err != nil {
+ switch e := err.(type) {
+ case fory.Error:
+ fmt.Printf("Fory error: %s (kind: %d)\n", e.Error(), e.Kind())
+ default:
+ fmt.Printf("Unknown error: %v\n", err)
+ }
+ return
+}
+
+err = f.Deserialize(data, &result)
+if err != nil {
+ // Handle deserialization error
+}
+```
+
+Common error kinds:
+
+- `ErrKindBufferOutOfBound`: Read/write beyond buffer bounds
+- `ErrKindTypeMismatch`: Type ID mismatch during deserialization
+- `ErrKindUnknownType`: Unknown type encountered
+- `ErrKindMaxDepthExceeded`: Recursion depth limit exceeded
+- `ErrKindHashMismatch`: Struct hash mismatch (schema changed)
+
+See [Troubleshooting](troubleshooting) for error resolution.
+
+## Nil Handling
+
+### Nil Pointers
+
+```go
+var ptr *User = nil
+data, _ := f.Serialize(ptr)
+
+var result *User
+f.Deserialize(data, &result)
+// result = nil
+```
+
+### Empty Collections
+
+```go
+// Nil slice
+var slice []string = nil
+data, _ := f.Serialize(slice)
+
+var result []string
+f.Deserialize(data, &result)
+// result = nil
+
+// Empty slice (different from nil)
+empty := []string{}
+data, _ = f.Serialize(empty)
+
+f.Deserialize(data, &result)
+// result = [] (empty, not nil)
+```
+
+## Complete Example
+
+```go
+package main
+
+import (
+ "fmt"
+ "github.com/apache/fory/go/fory"
+)
+
+type Order struct {
+ ID int64
+ Customer string
+ Items []Item
+ Total float64
+}
+
+type Item struct {
+ Name string
+ Quantity int32
+ Price float64
+}
+
+func main() {
+ f := fory.New()
+ f.RegisterStruct(Order{}, 1)
+ f.RegisterStruct(Item{}, 2)
+
+ order := &Order{
+ ID: 12345,
+ Customer: "Alice",
+ Items: []Item{
+ {Name: "Widget", Quantity: 2, Price: 9.99},
+ {Name: "Gadget", Quantity: 1, Price: 24.99},
+ },
+ Total: 44.97,
+ }
+
+ // Serialize
+ data, err := f.Serialize(order)
+ if err != nil {
+ panic(err)
+ }
+ fmt.Printf("Serialized %d bytes\n", len(data))
+
+ // Deserialize
+ var result Order
+ if err := f.Deserialize(data, &result); err != nil {
+ panic(err)
+ }
+
+ fmt.Printf("Order ID: %d\n", result.ID)
+ fmt.Printf("Customer: %s\n", result.Customer)
+ fmt.Printf("Items: %d\n", len(result.Items))
+ fmt.Printf("Total: %.2f\n", result.Total)
+}
+```
+
+## Related Topics
+
+- [Configuration](configuration)
+- [Type Registration](type-registration)
+- [Supported Types](supported-types)
+- [References](references)
diff --git a/docs/docs/guide/go/codegen.md b/docs/docs/guide/go/codegen.md
new file mode 100644
index 000000000..dd08a751b
--- /dev/null
+++ b/docs/docs/guide/go/codegen.md
@@ -0,0 +1,420 @@
+---
+title: Code Generation
+sidebar_position: 90
+id: go_codegen
+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
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+---
+
+:::warning Experimental Feature
+Code generation is an **experimental** feature in Fory Go. The API and
behavior may change in future releases. The reflection-based path remains the
stable, recommended approach for most use cases.
+:::
+
+Fory Go provides optional ahead-of-time (AOT) code generation for
performance-critical paths. This eliminates reflection overhead and provides
compile-time type safety.
+
+## Why Code Generation?
+
+| Aspect | Reflection-Based | Code Generation |
+| ----------- | ------------------ | ---------------------- |
+| Setup | Zero configuration | Requires `go generate` |
+| Performance | Good | Better (no reflection) |
+| Type Safety | Runtime | Compile-time |
+| Maintenance | Automatic | Requires regeneration |
+
+**Use code generation when**:
+
+- Maximum performance is required
+- Compile-time type safety is important
+- Hot paths are performance-critical
+
+**Use reflection when**:
+
+- Simple setup is preferred
+- Types change frequently
+- Dynamic typing is needed
+- Code generation complexity is undesirable
+
+## Installation
+
+Install the `fory` generator binary:
+
+```bash
+go install github.com/apache/fory/go/fory/cmd/fory@latest
+
+GO111MODULE=on go get -u github.com/apache/fory/go/fory/cmd/fory
+```
+
+Ensure `$GOBIN` or `$GOPATH/bin` is in your `PATH`.
+
+## Basic Usage
+
+### Step 1: Annotate Structs
+
+Add the `//fory:generate` comment above structs:
+
+```go
+package models
+
+//fory:generate
+type User struct {
+ ID int64 `json:"id"`
+ Name string `json:"name"`
+}
+
+//fory:generate
+type Order struct {
+ ID int64
+ Customer string
+ Total float64
+}
+```
+
+### Step 2: Add Go Generate Directive
+
+Add a `go:generate` directive (once per file or package):
+
+```go
+//go:generate fory -file models.go
+```
+
+Or for the entire package:
+
+```go
+//go:generate fory -pkg .
+```
+
+### Step 3: Run Code Generation
+
+```bash
+go generate ./...
+```
+
+This creates `models_fory_gen.go` with generated serializers.
+
+## Generated Code Structure
+
+The generator creates:
+
+### Type Snapshot
+
+A compile-time check to detect struct changes:
+
+```go
+// Snapshot of User's underlying type at generation time
+type _User_expected struct {
+ ID int64
+ Name string
+}
+
+// Compile-time check: fails if User no longer matches
+var _ = func(x User) { _ = _User_expected(x) }
+```
+
+### Serializer Implementation
+
+Strongly-typed serialization methods:
+
+```go
+type User_ForyGenSerializer struct{}
+
+func (User_ForyGenSerializer) WriteTyped(f *fory.Fory, buf *fory.ByteBuffer, v
*User) error {
+ buf.WriteInt64(v.ID)
+ fory.WriteString(buf, v.Name)
+ return nil
+}
+
+func (User_ForyGenSerializer) ReadTyped(f *fory.Fory, buf *fory.ByteBuffer, v
*User) error {
+ v.ID = buf.ReadInt64()
+ v.Name = fory.ReadString(buf)
+ return nil
+}
+```
+
+### Auto-Registration
+
+Serializers are registered in `init()`:
+
+```go
+func init() {
+ fory.RegisterGenSerializer(User{}, User_ForyGenSerializer{})
+}
+```
+
+## Command-Line Options
+
+### File-Based Generation
+
+Generate for a specific file:
+
+```bash
+fory -file models.go
+```
+
+### Package-Based Generation
+
+Generate for a package:
+
+```bash
+fory -pkg ./models
+```
+
+### Explicit Types (Legacy)
+
+Specify types explicitly:
+
+```bash
+fory -pkg ./models -type "User,Order"
+```
+
+### Force Regeneration
+
+Force regeneration even if up-to-date:
+
+```bash
+fory --force -file models.go
+```
+
+## When to Regenerate
+
+Regenerate when any of these change:
+
+- Field additions, removals, or renames
+- Field type changes
+- Struct tag changes
+- New structs with `//fory:generate`
+
+### Automatic Detection
+
+Fory includes a compile-time guard:
+
+```go
+// If struct changed, this fails to compile
+var _ = func(x User) { _ = _User_expected(x) }
+```
+
+If you forget to regenerate, the build fails with a clear message.
+
+### Auto-Retry
+
+When invoked via `go generate`, the generator detects stale code and retries:
+
+1. Detects compile error from guard
+2. Removes stale generated file
+3. Regenerates fresh code
+
+## Supported Types
+
+Code generation supports:
+
+- All primitive types (`bool`, `int*`, `uint*`, `float*`, `string`)
+- Slices of primitives and structs
+- Maps with supported key/value types
+- Nested structs (must also be generated)
+- Pointers to structs
+
+### Nested Structs
+
+All nested structs must also have `//fory:generate`:
+
+```go
+//fory:generate
+type Address struct {
+ City string
+ Country string
+}
+
+//fory:generate
+type Person struct {
+ Name string
+ Address Address // Address must also be generated
+}
+```
+
+## CI/CD Integration
+
+### Check In Generated Code
+
+**Recommended for libraries**:
+
+```bash
+go generate ./...
+git add *_fory_gen.go
+git commit -m "Regenerate Fory serializers"
+```
+
+**Pros**: Consumers can build without generator; reproducible builds
+**Cons**: Larger diffs; must remember to regenerate
+
+### Generate in Pipeline
+
+**Recommended for applications**:
+
+```yaml
+steps:
+ - run: go install github.com/apache/fory/go/fory/cmd/fory@latest
+ - run: go generate ./...
+ - run: go build ./...
+```
+
+## Usage with Generated Code
+
+Generated code integrates transparently:
+
+```go
+f := fory.New()
+
+// Fory automatically uses generated serializer if available
+user := &User{ID: 1, Name: "Alice"}
+data, _ := f.Serialize(user)
+
+var result User
+f.Deserialize(data, &result)
+```
+
+No code changes needed - registration happens in `init()`.
+
+## Mixing Generated and Non-Generated
+
+You can mix approaches:
+
+```go
+//fory:generate
+type HotPathStruct struct {
+ // Performance-critical, use codegen
+}
+
+type ColdPathStruct struct {
+ // Not annotated, uses reflection
+}
+```
+
+## Limitations
+
+### Experimental Status
+
+- API may change
+- Not all edge cases tested
+- May have undiscovered bugs
+
+### Not Supported
+
+- Interface fields (dynamic types)
+- Recursive types without pointers
+- Private (unexported) fields
+- Custom serializers
+
+### Reflection Fallback
+
+If codegen fails, Fory falls back to reflection:
+
+```go
+// If User_ForyGenSerializer not found, uses reflection
+f.Serialize(&User{})
+```
+
+## Troubleshooting
+
+### "fory: command not found"
+
+Ensure the binary is in PATH:
+
+```bash
+export PATH=$PATH:$(go env GOPATH)/bin
+```
+
+### Compile Error After Struct Change
+
+Regenerate:
+
+```bash
+go generate ./...
+```
+
+Or force:
+
+```bash
+fory --force -file yourfile.go
+```
+
+### Generated Code Out of Sync
+
+The compile-time guard catches this:
+
+```
+cannot use x (variable of type User) as type _User_expected in argument
+```
+
+Run `go generate` to fix.
+
+## Example Project Structure
+
+```
+myproject/
+├── models/
+│ ├── models.go # Struct definitions
+│ ├── models_fory_gen.go # Generated code
+│ └── generate.go # go:generate directive
+├── main.go
+└── go.mod
+```
+
+**models/generate.go**:
+
+```go
+package models
+
+//go:generate fory -pkg .
+```
+
+**models/models.go**:
+
+```go
+package models
+
+//fory:generate
+type User struct {
+ ID int64
+ Name string
+}
+```
+
+## FAQ
+
+### Is codegen required?
+
+No. Reflection-based serialization works without code generation.
+
+### Does generated code work across Go versions?
+
+Yes. Generated code is plain Go with no version-specific features.
+
+### Can I mix generated and non-generated types?
+
+Yes. Fory automatically uses generated serializers when available.
+
+### How do I update generated code?
+
+Run `go generate ./...` after struct changes.
+
+### Should I commit generated files?
+
+For libraries: yes. For applications: either works.
+
+## Related Topics
+
+- [Basic Serialization](basic-serialization)
+- [Configuration](configuration)
+- [Troubleshooting](troubleshooting)
diff --git a/docs/docs/guide/go/configuration.md
b/docs/docs/guide/go/configuration.md
new file mode 100644
index 000000000..f9414a7c6
--- /dev/null
+++ b/docs/docs/guide/go/configuration.md
@@ -0,0 +1,344 @@
+---
+title: Configuration
+sidebar_position: 10
+id: go_configuration
+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
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+---
+
+Fory Go uses a functional options pattern for configuration. This allows you
to customize serialization behavior while maintaining sensible defaults.
+
+## Creating a Fory Instance
+
+### Default Configuration
+
+```go
+import "github.com/apache/fory/go/fory"
+
+f := fory.New()
+```
+
+Default settings:
+
+| Option | Default | Description |
+| ---------- | ------- | ------------------------------ |
+| TrackRef | false | Reference tracking disabled |
+| MaxDepth | 20 | Maximum nesting depth |
+| IsXlang | false | Cross-language mode disabled |
+| Compatible | false | Schema evolution mode disabled |
+
+### With Options
+
+```go
+f := fory.New(
+ fory.WithTrackRef(true),
+ fory.WithCompatible(true),
+ fory.WithMaxDepth(10),
+)
+```
+
+## Configuration Options
+
+### WithTrackRef
+
+Enable reference tracking to handle circular references and shared objects:
+
+```go
+f := fory.New(fory.WithTrackRef(true))
+```
+
+**When enabled:**
+
+- Objects appearing multiple times are serialized once
+- Circular references are handled correctly
+- Per-field `fory:"ref"` tags take effect
+- Adds overhead for tracking object identity
+
+**When disabled (default):**
+
+- Each object occurrence is serialized independently
+- Circular references cause stack overflow or max depth error
+- Per-field `fory:"ref"` tags are ignored
+- Better performance for simple data structures
+
+**Use reference tracking when:**
+
+- Data contains circular references
+- Same object is referenced multiple times
+- Serializing graph structures (trees with parent pointers, linked lists with
cycles)
+
+See [References](references) for details.
+
+### WithCompatible
+
+Enable compatible mode for schema evolution:
+
+```go
+f := fory.New(fory.WithCompatible(true))
+```
+
+**When enabled:**
+
+- Type metadata is written to serialized data
+- Supports adding/removing fields between versions
+- Field names or ids are used for matching (order-independent)
+- Larger serialized output due to metadata
+
+**When disabled (default):**
+
+- Compact serialization without field metadata
+- Faster serialization and smaller output
+- Fields matched by sorted order
+- Requires consistent struct definitions across all services
+
+See [Schema Evolution](schema-evolution) for details.
+
+### WithMaxDepth
+
+Set the maximum nesting depth to prevent stack overflow:
+
+```go
+f := fory.New(fory.WithMaxDepth(30))
+```
+
+- Default: 20
+- Protects against deeply nested, recursive structures or malicious data
+- Serialization fails with error when exceeded
+
+### WithXlang
+
+Enable cross-language serialization mode:
+
+```go
+f := fory.New(fory.WithXlang(true))
+```
+
+**When enabled:**
+
+- Uses cross-language type system
+- Compatible with Java, Python, C++, Rust, JavaScript
+- Type IDs follow xlang specification
+
+**When disabled (default):**
+
+- Go-native serialization mode
+- Support more Go-native types
+- Not compatible with other language implementations
+
+## Thread Safety
+
+The default `Fory` instance is **NOT thread-safe**. For concurrent use, use
the thread-safe wrapper:
+
+```go
+import "github.com/apache/fory/go/fory/threadsafe"
+
+// Create thread-safe Fory with same options
+f := threadsafe.New(
+ fory.WithTrackRef(true),
+ fory.WithCompatible(true),
+)
+
+// Safe for concurrent use from multiple goroutines
+go func() {
+ data, _ := f.Serialize(value1)
+ // data is already copied, safe to use after return
+}()
+go func() {
+ data, _ := f.Serialize(value2)
+}()
+```
+
+The thread-safe wrapper:
+
+- Uses `sync.Pool` internally for efficient instance reuse
+- Automatically copies serialized data before returning
+- Accepts the same configuration options as `fory.New()`
+
+### Global Thread-Safe Instance
+
+For convenience, the threadsafe package provides global functions:
+
+```go
+import "github.com/apache/fory/go/fory/threadsafe"
+
+// Uses a global thread-safe instance with default configuration
+data, err := threadsafe.Marshal(&myValue)
+err = threadsafe.Unmarshal(data, &result)
+```
+
+See [Thread Safety](thread-safety) for details.
+
+## Buffer Management
+
+### Zero-Copy Behavior
+
+The default `Fory` instance reuses its internal buffer:
+
+```go
+f := fory.New()
+
+data1, _ := f.Serialize(value1)
+// WARNING: data1 becomes invalid after next Serialize call!
+data2, _ := f.Serialize(value2)
+// data1 now points to invalid memory
+
+// To keep the data, copy it:
+safeCopy := make([]byte, len(data1))
+copy(safeCopy, data1)
+```
+
+The thread-safe wrapper automatically copies data, so this is not a concern:
+
+```go
+f := threadsafe.New()
+data1, _ := f.Serialize(value1)
+data2, _ := f.Serialize(value2)
+// Both data1 and data2 are valid
+```
+
+### Manual Buffer Control
+
+For high-throughput scenarios, you can manage buffers manually:
+
+```go
+f := fory.New()
+buf := fory.NewByteBuffer(nil)
+
+// Serialize to existing buffer
+err := f.SerializeTo(buf, value)
+
+// Get serialized data
+data := buf.GetByteSlice(0, buf.WriterIndex())
+
+// Process data...
+
+// Reset for next use
+buf.Reset()
+```
+
+## Configuration Examples
+
+### Simple Data (Default)
+
+For simple structs without circular references:
+
+```go
+f := fory.New()
+
+type Config struct {
+ Host string
+ Port int32
+}
+
+f.RegisterStruct(Config{}, 1)
+data, _ := f.Serialize(&Config{Host: "localhost", Port: 8080})
+```
+
+### Graph Structures
+
+For data with circular references:
+
+```go
+f := fory.New(fory.WithTrackRef(true))
+
+type Node struct {
+ Value int32
+ Next *Node `fory:"ref"`
+}
+
+f.RegisterStruct(Node{}, 1)
+n1 := &Node{Value: 1}
+n2 := &Node{Value: 2}
+n1.Next = n2
+n2.Next = n1 // Circular reference
+
+data, _ := f.Serialize(n1)
+```
+
+### Schema Evolution
+
+For data that may evolve over time:
+
+```go
+// V1: original struct
+type UserV1 struct {
+ ID int64
+ Name string
+}
+
+// V2: added Email field
+type UserV2 struct {
+ ID int64
+ Name string
+ Email string // New field
+}
+
+// Serialize with V1
+f1 := fory.New(fory.WithCompatible(true))
+f1.RegisterStruct(UserV1{}, 1)
+data, _ := f1.Serialize(&UserV1{ID: 1, Name: "Alice"})
+
+// Deserialize into V2 - Email will have zero value
+f2 := fory.New(fory.WithCompatible(true))
+f2.RegisterStruct(UserV2{}, 1)
+var user UserV2
+f2.Deserialize(data, &user)
+```
+
+### High-Performance Concurrent
+
+For concurrent high-throughput scenarios:
+
+```go
+type Request struct {
+ ID int64
+ Payload string
+}
+
+f := threadsafe.New(
+ fory.WithMaxDepth(30),
+)
+f.RegisterStruct(Request{}, 1)
+
+// Process requests concurrently
+for req := range requests {
+ go func(r Request) {
+ data, _ := f.Serialize(&r)
+ sendResponse(data)
+ }(req)
+}
+```
+
+## Best Practices
+
+1. **Reuse Fory instances**: Creating a Fory instance involves initialization
overhead. Create once and reuse.
+
+2. **Use thread-safe wrapper for concurrency**: Never share a non-thread-safe
Fory instance across goroutines.
+
+3. **Enable reference tracking only when needed**: It adds overhead for
tracking object identity.
+
+4. **Copy serialized data if keeping it**: With the default Fory, the returned
byte slice is invalidated on the next operation.
+
+5. **Set appropriate max depth**: Increase for deeply nested structures, but
be aware of memory usage.
+
+6. **Use compatible mode for evolving schemas**: Enable when struct
definitions may change between service versions.
+
+## Related Topics
+
+- [Basic Serialization](basic-serialization)
+- [References](references)
+- [Schema Evolution](schema-evolution)
+- [Thread Safety](thread-safety)
diff --git a/docs/docs/guide/go/cross-language.md
b/docs/docs/guide/go/cross-language.md
new file mode 100644
index 000000000..f10fa97c5
--- /dev/null
+++ b/docs/docs/guide/go/cross-language.md
@@ -0,0 +1,282 @@
+---
+title: Cross-Language Serialization
+sidebar_position: 80
+id: go_cross_language
+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
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+---
+
+Fory Go enables seamless data exchange with Java, Python, C++, Rust, and
JavaScript. This guide covers cross-language compatibility and type mapping.
+
+## Enabling Cross-Language Mode
+
+Cross-language (xlang) mode must be explicitly enabled:
+
+```go
+f := fory.New(fory.WithXlang(true))
+```
+
+## Type Registration for Cross-Language
+
+Use consistent type IDs across all languages:
+
+### Go
+
+```go
+type User struct {
+ ID int64
+ Name string
+}
+
+f := fory.New(fory.WithXlang(true))
+f.RegisterStruct(User{}, 1)
+data, _ := f.Serialize(&User{ID: 1, Name: "Alice"})
+```
+
+### Java
+
+```java
+public class User {
+ public long id;
+ public String name;
+}
+Fory fory = Fory.builder().withXlang(true).build();
+fory.register(User.class, 1);
+User user = fory.deserialize(data, User.class);
+```
+
+### Python
+
+```python
+from dataclasses import dataclass
+import pyfory
+
+@dataclass
+class User:
+ id: pyfory.Int64Type
+ name: str
+
+fory = pyfory.Fory()
+fory.register(User, type_id=1)
+user = fory.deserialize(data)
+```
+
+## Type Mapping
+
+See [Type Mapping
Specification](https://fory.apache.org/docs/specification/xlang_type_mapping)
for detailed type mappings across all languages.
+
+## Field Ordering
+
+Cross-language serialization requires consistent field ordering. Fory sorts
fields by their snake_case names alphabetically.
+
+Go field names are converted to snake_case for sorting:
+
+```go
+type Example struct {
+ UserID int64 // -> user_id
+ FirstName string // -> first_name
+ Age int32 // -> age
+}
+
+// Sorted order: age, first_name, user_id
+```
+
+Ensure other languages use matching field names that produce the same
snake_case ordering, or use field IDs for explicit control:
+
+```go
+type Example struct {
+ UserID int64 `fory:"id=0"`
+ FirstName string `fory:"id=1"`
+ Age int32 `fory:"id=2"`
+}
+```
+
+## Examples
+
+### Go to Java
+
+**Go (Serializer)**:
+
+```go
+type Order struct {
+ ID int64
+ Customer string
+ Total float64
+ Items []string
+}
+
+f := fory.New(fory.WithXlang(true))
+f.RegisterStruct(Order{}, 1)
+
+order := &Order{
+ ID: 12345,
+ Customer: "Alice",
+ Total: 99.99,
+ Items: []string{"Widget", "Gadget"},
+}
+data, _ := f.Serialize(order)
+// Send 'data' to Java service
+```
+
+**Java (Deserializer)**:
+
+```java
+public class Order {
+ public long id;
+ public String customer;
+ public double total;
+ public List<String> items;
+}
+
+Fory fory = Fory.builder().withXlang(true).build();
+fory.register(Order.class, 1);
+
+Order order = fory.deserialize(data, Order.class);
+```
+
+### Python to Go
+
+**Python (Serializer)**:
+
+```python
+from dataclasses import dataclass
+import pyfory
+
+@dataclass
+class Message:
+ id: pyfory.Int64Type
+ content: str
+ timestamp: pyfory.Int64Type
+
+fory = pyfory.Fory()
+fory.register(Message, type_id=1)
+
+msg = Message(id=1, content="Hello from Python", timestamp=1234567890)
+data = fory.serialize(msg)
+```
+
+**Go (Deserializer)**:
+
+```go
+type Message struct {
+ ID int64
+ Content string
+ Timestamp int64
+}
+
+f := fory.New(fory.WithXlang(true))
+f.RegisterStruct(Message{}, 1)
+
+var msg Message
+f.Deserialize(data, &msg)
+fmt.Println(msg.Content) // "Hello from Python"
+```
+
+### Nested Structures
+
+Cross-language nested structures require all types to be registered:
+
+**Go**:
+
+```go
+type Address struct {
+ Street string
+ City string
+ Country string
+}
+
+type Company struct {
+ Name string
+ Address Address
+}
+
+f := fory.New(fory.WithXlang(true))
+f.RegisterStruct(Address{}, 1)
+f.RegisterStruct(Company{}, 2)
+```
+
+**Java**:
+
+```java
+public class Address {
+ public String street;
+ public String city;
+ public String country;
+}
+
+public class Company {
+ public String name;
+ public Address address;
+}
+
+fory.register(Address.class, 1);
+fory.register(Company.class, 2);
+```
+
+## Common Issues
+
+### Field Name Mismatch
+
+Go uses PascalCase, other languages may use camelCase or snake_case. Fields
are matched by their snake_case conversion:
+
+```go
+// Go
+type User struct {
+ FirstName string // -> first_name
+}
+
+// Java - field name converted to snake_case must match
+public class User {
+ public String firstName; // -> first_name (matches)
+}
+```
+
+### Type Interpretation
+
+Go unsigned types map to Java signed types with the same bit pattern:
+
+```go
+var value uint64 = 18446744073709551615 // Max uint64
+```
+
+Java's `long` holds the same bits but interprets as -1. Use
`Long.toUnsignedString()` in Java if unsigned interpretation is needed.
+
+### Nil vs Null
+
+Go nil slices/maps serialize differently based on configuration:
+
+```go
+var slice []string = nil
+// In xlang mode: serializes based on nullable configuration
+```
+
+Ensure other languages handle null appropriately.
+
+## Best Practices
+
+1. **Use consistent type IDs**: Same numeric ID for the same type across all
languages
+2. **Register all types**: Including nested struct types
+3. **Match field ordering**: Use same snake_case names or explicit field IDs
+4. **Test cross-language**: Run integration tests early and often
+5. **Handle type differences**: Be aware of signed/unsigned interpretation
differences
+
+## Related Topics
+
+- [Type Registration](type-registration)
+- [Supported Types](supported-types)
+- [Schema Evolution](schema-evolution)
+- [Xlang Serialization
Specification](https://fory.apache.org/docs/specification/fory_xlang_serialization_spec/)
+- [Type Mapping
Specification](https://fory.apache.org/docs/specification/xlang_type_mapping)
diff --git a/docs/docs/guide/go/custom-serializers.md
b/docs/docs/guide/go/custom-serializers.md
new file mode 100644
index 000000000..3bf940faf
--- /dev/null
+++ b/docs/docs/guide/go/custom-serializers.md
@@ -0,0 +1,285 @@
+---
+title: Custom Serializers
+sidebar_position: 35
+id: go_custom_serializers
+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
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+---
+
+Custom serializers allow you to define exactly how a type is serialized and
deserialized. This is useful for types that require special handling,
optimization, or cross-language compatibility.
+
+## When to Use Custom Serializers
+
+- **Special encoding**: Types that need a specific binary format
+- **Third-party types**: Types from external libraries that Fory doesn't
handle automatically
+- **Optimization**: When you can serialize more efficiently than the default
reflection-based approach
+- **Cross-language compatibility**: When you need precise control over the
binary format for interoperability
+
+## ExtensionSerializer Interface
+
+Custom serializers implement the `ExtensionSerializer` interface:
+
+```go
+type ExtensionSerializer interface {
+ // WriteData serializes the value to the buffer.
+ // Only write the data - Fory handles type info and references.
+ // Use ctx.Buffer() to access the ByteBuffer.
+ // Use ctx.SetError() to report errors.
+ WriteData(ctx *WriteContext, value reflect.Value)
+
+ // ReadData deserializes the value from the buffer into the provided value.
+ // Only read the data - Fory handles type info and references.
+ // Use ctx.Buffer() to access the ByteBuffer.
+ // Use ctx.SetError() to report errors.
+ ReadData(ctx *ReadContext, value reflect.Value)
+}
+```
+
+## Basic Example
+
+Here's a simple custom serializer for a type with an integer field:
+
+```go
+import (
+ "reflect"
+ "github.com/apache/fory/go/fory"
+)
+
+type MyExt struct {
+ Id int32
+}
+
+type MyExtSerializer struct{}
+
+func (s *MyExtSerializer) WriteData(ctx *fory.WriteContext, value
reflect.Value) {
+ myExt := value.Interface().(MyExt)
+ ctx.Buffer().WriteVarint32(myExt.Id)
+}
+
+func (s *MyExtSerializer) ReadData(ctx *fory.ReadContext, value reflect.Value)
{
+ id := ctx.Buffer().ReadVarint32(ctx.Err())
+ value.Set(reflect.ValueOf(MyExt{Id: id}))
+}
+
+// Register the custom serializer
+f := fory.New()
+err := f.RegisterExtension(MyExt{}, 100, &MyExtSerializer{})
+```
+
+## Context Methods
+
+The `WriteContext` and `ReadContext` provide access to serialization resources:
+
+| Method | Description |
+| ---------------- | ---------------------------------------------- |
+| `Buffer()` | Returns the `*ByteBuffer` for reading/writing |
+| `Err()` | Returns `*Error` for deferred error checking |
+| `SetError(err)` | Sets an error on the context |
+| `HasError()` | Returns true if an error has been set |
+| `TypeResolver()` | Returns the type resolver for nested types |
+| `RefResolver()` | Returns the reference resolver for ref support |
+
+## ByteBuffer Methods
+
+The `ByteBuffer` provides methods for reading and writing primitive types:
+
+### Writing Methods
+
+| Method | Description |
+| -------------------------- | --------------------------------------------- |
+| `WriteBool(v bool)` | Write a boolean |
+| `WriteInt8(v int8)` | Write a signed 8-bit integer |
+| `WriteInt16(v int16)` | Write a signed 16-bit integer |
+| `WriteInt32(v int32)` | Write a signed 32-bit integer |
+| `WriteInt64(v int64)` | Write a signed 64-bit integer |
+| `WriteFloat32(v float32)` | Write a 32-bit float |
+| `WriteFloat64(v float64)` | Write a 64-bit float |
+| `WriteVarint32(v int32)` | Write a variable-length signed 32-bit integer |
+| `WriteVarint64(v int64)` | Write a variable-length signed 64-bit integer |
+| `WriteBinary(data []byte)` | Write raw bytes |
+
+### Reading Methods
+
+All read methods take an `*Error` parameter for deferred error checking:
+
+| Method | Description
|
+| ------------------------------------------- |
-------------------------------------------- |
+| `ReadBool(err *Error) bool` | Read a boolean
|
+| `ReadInt8(err *Error) int8` | Read a signed 8-bit integer
|
+| `ReadInt16(err *Error) int16` | Read a signed 16-bit integer
|
+| `ReadInt32(err *Error) int32` | Read a signed 32-bit integer
|
+| `ReadInt64(err *Error) int64` | Read a signed 64-bit integer
|
+| `ReadFloat32(err *Error) float32` | Read a 32-bit float
|
+| `ReadFloat64(err *Error) float64` | Read a 64-bit float
|
+| `ReadVarint32(err *Error) int32` | Read a variable-length signed
32-bit integer |
+| `ReadVarint64(err *Error) int64` | Read a variable-length signed
64-bit integer |
+| `ReadBinary(length int, err *Error) []byte` | Read raw bytes of specified
length |
+
+## Complex Type Example
+
+A custom serializer for a type with multiple fields:
+
+```go
+type Point3D struct {
+ X, Y, Z float64
+ Label string
+}
+
+type Point3DSerializer struct{}
+
+func (s *Point3DSerializer) WriteData(ctx *fory.WriteContext, value
reflect.Value) {
+ p := value.Interface().(Point3D)
+ buf := ctx.Buffer()
+ buf.WriteFloat64(p.X)
+ buf.WriteFloat64(p.Y)
+ buf.WriteFloat64(p.Z)
+ // Write string as length + bytes
+ labelBytes := []byte(p.Label)
+ buf.WriteVarint32(int32(len(labelBytes)))
+ buf.WriteBinary(labelBytes)
+}
+
+func (s *Point3DSerializer) ReadData(ctx *fory.ReadContext, value
reflect.Value) {
+ buf := ctx.Buffer()
+ err := ctx.Err()
+ x := buf.ReadFloat64(err)
+ y := buf.ReadFloat64(err)
+ z := buf.ReadFloat64(err)
+ labelLen := buf.ReadVarint32(err)
+ labelBytes := buf.ReadBinary(int(labelLen), err)
+ value.Set(reflect.ValueOf(Point3D{
+ X: x,
+ Y: y,
+ Z: z,
+ Label: string(labelBytes),
+ }))
+}
+
+f := fory.New()
+f.RegisterExtension(Point3D{}, 101, &Point3DSerializer{})
+```
+
+## Handling Pointers
+
+When your type contains pointers, handle nil values explicitly:
+
+```go
+type OptionalValue struct {
+ Value *int64
+}
+
+type OptionalValueSerializer struct{}
+
+func (s *OptionalValueSerializer) WriteData(ctx *fory.WriteContext, value
reflect.Value) {
+ ov := value.Interface().(OptionalValue)
+ buf := ctx.Buffer()
+ if ov.Value == nil {
+ buf.WriteBool(false) // nil flag
+ } else {
+ buf.WriteBool(true) // not nil
+ buf.WriteInt64(*ov.Value)
+ }
+}
+
+func (s *OptionalValueSerializer) ReadData(ctx *fory.ReadContext, value
reflect.Value) {
+ buf := ctx.Buffer()
+ err := ctx.Err()
+ hasValue := buf.ReadBool(err)
+ if !hasValue {
+ value.Set(reflect.ValueOf(OptionalValue{Value: nil}))
+ return
+ }
+ v := buf.ReadInt64(err)
+ value.Set(reflect.ValueOf(OptionalValue{Value: &v}))
+}
+```
+
+## Error Handling
+
+Use `ctx.SetError()` to report errors:
+
+```go
+func (s *MySerializer) ReadData(ctx *fory.ReadContext, value reflect.Value) {
+ buf := ctx.Buffer()
+ version := buf.ReadInt8(ctx.Err())
+ if ctx.HasError() {
+ return
+ }
+ if version != 1 {
+ ctx.SetError(fory.DeserializationErrorf("unsupported version: %d",
version))
+ return
+ }
+ // Continue reading...
+ value.Set(reflect.ValueOf(result))
+}
+```
+
+## Registration Options
+
+### Register by ID
+
+More compact serialization, requires ID coordination across languages:
+
+```go
+f.RegisterExtension(MyType{}, 100, &MySerializer{})
+```
+
+### Register by Name
+
+More flexible but more serialization cost, type name included in serialized
data:
+
+```go
+f.RegisterNamedExtension(MyType{}, "myapp.MyType", &MySerializer{})
+```
+
+## Best Practices
+
+1. **Keep it simple**: Only serialize what you need
+2. **Use variable-length integers**: `WriteVarint32`/`WriteVarint64` for
integers that are often small
+3. **Handle nil explicitly**: Check for nil pointers and slices
+4. **Version your format**: Consider adding a version byte for future
compatibility
+5. **Test round-trips**: Always verify that `Read(Write(value)) == value`
+6. **Match read/write order**: Read fields in exactly the same order you write
them
+7. **Check errors**: Use `ctx.HasError()` after reading to handle errors
gracefully
+8. **Deploy before use**: Always deploy the registered serializer to all
services before sending data serialized with it. If a service receives data for
an unregistered serializer, deserialization will fail
+
+## Testing Custom Serializers
+
+```go
+func TestMySerializer(t *testing.T) {
+ f := fory.New()
+ f.RegisterExtension(MyType{}, 100, &MySerializer{})
+
+ original := MyType{Field: "test"}
+
+ // Serialize
+ data, err := f.Serialize(original)
+ require.NoError(t, err)
+
+ // Deserialize
+ var result MyType
+ err = f.Deserialize(data, &result)
+ require.NoError(t, err)
+
+ assert.Equal(t, original, result)
+}
+```
+
+## Related Topics
+
+- [Type Registration](type-registration)
+- [Supported Types](supported-types)
+- [Cross-Language Serialization](cross-language)
diff --git a/docs/docs/guide/go/index.md b/docs/docs/guide/go/index.md
new file mode 100644
index 000000000..cbfe87afe
--- /dev/null
+++ b/docs/docs/guide/go/index.md
@@ -0,0 +1,162 @@
+---
+title: Overview
+sidebar_position: 0
+id: go_index
+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
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+---
+
+Apache Fory Go is a high-performance, cross-language serialization library for
Go. It provides automatic object graph serialization with support for circular
references, polymorphism, and cross-language compatibility.
+
+## Why Fory Go?
+
+- **High Performance**: Fast serialization and optimized binary protocols
+- **Cross-Language**: Seamless data exchange with Java, Python, C++, Rust, and
JavaScript
+- **Automatic Serialization**: No IDL definitions or schema compilation
required
+- **Reference Tracking**: Built-in support for circular references and shared
objects
+- **Type Safety**: Strong typing with compile-time verification (optional
codegen)
+- **Schema Evolution**: Compatible mode for forward/backward compatibility
+- **Thread-Safe Option**: Pool-based thread-safe wrapper for concurrent use
+
+## Quick Start
+
+### Installation
+
+```bash
+go get github.com/apache/fory/go/fory
+```
+
+### Basic Usage
+
+```go
+package main
+
+import (
+ "fmt"
+ "github.com/apache/fory/go/fory"
+)
+
+type User struct {
+ ID int64
+ Name string
+ Age int32
+}
+
+func main() {
+ // Create a Fory instance
+ f := fory.New()
+
+ // Register struct with a type ID
+ if err := f.RegisterStruct(User{}, 1); err != nil {
+ panic(err)
+ }
+
+ // Serialize
+ user := &User{ID: 1, Name: "Alice", Age: 30}
+ data, err := f.Serialize(user)
+ if err != nil {
+ panic(err)
+ }
+
+ // Deserialize
+ var result User
+ if err := f.Deserialize(data, &result); err != nil {
+ panic(err)
+ }
+
+ fmt.Printf("Deserialized: %+v\n", result)
+ // Output: Deserialized: {ID:1 Name:Alice Age:30}
+}
+```
+
+## Architecture
+
+Fory Go provides two serialization paths:
+
+### Reflection-Based (Default)
+
+The default path uses Go's reflection to inspect types at runtime. This works
out-of-the-box with any struct. Although this mode uses reflection, it is
highly optimized with type caching, inlined hot paths, delivering excellent
performance for most use cases:
+
+```go
+f := fory.New()
+data, _ := f.Serialize(myStruct)
+```
+
+### Code Generation (Experimental)
+
+For performance-critical paths, Fory provides optional ahead-of-time code
generation that eliminates reflection overhead. See the [Code
Generation](codegen) guide for details.
+
+## Configuration
+
+Fory Go uses a functional options pattern for configuration:
+
+```go
+f := fory.New(
+ fory.WithTrackRef(true), // Enable reference tracking
+ fory.WithCompatible(true), // Enable schema evolution
+ fory.WithMaxDepth(20), // Set max nesting depth
+)
+```
+
+See [Configuration](configuration) for all available options.
+
+## Supported Types
+
+Fory Go supports a wide range of types:
+
+- **Primitives**: `bool`, `int8`-`int64`, `uint8`-`uint64`, `float32`,
`float64`, `string`
+- **Collections**: slices, maps, sets
+- **Time**: `time.Time`, `time.Duration`
+- **Pointers**: pointer types with automatic nil handling
+- **Structs**: any struct with exported fields
+
+See [Supported Types](supported-types) for the complete type mapping.
+
+## Cross-Language Serialization
+
+Fory Go is fully compatible with other Fory implementations. Data serialized
in Go can be deserialized in Java, Python, C++, Rust, or JavaScript:
+
+```go
+// Go serialization
+f := fory.New()
+f.RegisterStruct(User{}, 1)
+data, _ := f.Serialize(&User{ID: 1, Name: "Alice"})
+// 'data' can be deserialized by Java, Python, etc.
+```
+
+See [Cross-Language Serialization](cross-language) for type mapping and
compatibility details.
+
+## Documentation
+
+| Topic | Description
|
+| ------------------------------------------ |
-------------------------------------- |
+| [Configuration](configuration) | Options and settings
|
+| [Basic Serialization](basic-serialization) | Core APIs and usage patterns
|
+| [Type Registration](type-registration) | Registering types for
serialization |
+| [Supported Types](supported-types) | Complete type support reference
|
+| [References](references) | Circular references and shared
objects |
+| [Struct Tags](struct-tags) | Field-level configuration
|
+| [Schema Evolution](schema-evolution) | Forward/backward compatibility
|
+| [Cross-Language](cross-language) | Multi-language serialization
|
+| [Code Generation](codegen) | Experimental AOT code
generation |
+| [Thread Safety](thread-safety) | Concurrent usage patterns
|
+| [Troubleshooting](troubleshooting) | Common issues and solutions
|
+
+## Related Resources
+
+- [Xlang Serialization
Specification](https://fory.apache.org/docs/specification/fory_xlang_serialization_spec)
+- [Cross-Language Type
Mapping](https://fory.apache.org/docs/specification/xlang_type_mapping)
+- [GitHub Repository](https://github.com/apache/fory)
diff --git a/docs/docs/guide/go/references.md b/docs/docs/guide/go/references.md
new file mode 100644
index 000000000..c1b34d2f6
--- /dev/null
+++ b/docs/docs/guide/go/references.md
@@ -0,0 +1,356 @@
+---
+title: References
+sidebar_position: 50
+id: go_references
+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
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+---
+
+Fory Go supports reference tracking to handle circular references and shared
objects. This is essential for serializing complex data structures like graphs,
trees with parent pointers, and linked lists with cycles.
+
+## Enabling Reference Tracking
+
+Reference tracking is **disabled by default**. Enable it when creating a Fory
instance:
+
+```go
+f := fory.New(fory.WithTrackRef(true))
+```
+
+**Important**: Global reference tracking must be enabled for any reference
tracking to occur. When `WithTrackRef(false)` (the default), all per-field
reference tags are ignored.
+
+## How Reference Tracking Works
+
+### Without Reference Tracking (Default)
+
+When disabled, each object is serialized independently:
+
+```go
+f := fory.New() // TrackRef disabled by default
+
+shared := &Data{Value: 42}
+container := &Container{A: shared, B: shared}
+
+data, _ := f.Serialize(container)
+// 'shared' is serialized TWICE (no deduplication)
+```
+
+### With Reference Tracking
+
+When enabled, objects are tracked by identity:
+
+```go
+f := fory.New(fory.WithTrackRef(true))
+
+shared := &Data{Value: 42}
+container := &Container{A: shared, B: shared}
+
+data, _ := f.Serialize(container)
+// 'shared' is serialized ONCE, second occurrence is a reference
+```
+
+## Reference Flags
+
+Fory uses flags to indicate reference states during serialization:
+
+| Flag | Value | Meaning |
+| ------------------ | ----- | ----------------------------------------- |
+| `NullFlag` | -3 | Nil/null value |
+| `RefFlag` | -2 | Reference to previously serialized object |
+| `NotNullValueFlag` | -1 | Non-null value (data follows) |
+| `RefValueFlag` | 0 | Reference value flag |
+
+## Referenceable Types
+
+Only certain types support reference tracking. In xlang mode, the following
types can track references:
+
+| Type | Reference Tracked | Notes
|
+| ----------------------------- | ----------------- |
------------------------------ |
+| `*struct` (pointer to struct) | Yes | Enable with `fory:"ref"`
tag |
+| `any` (interface) | Yes | Automatically tracked
|
+| `[]T` (slices) | Yes | Enable with `fory:"ref"`
tag |
+| `map[K]V` | Yes | Enable with `fory:"ref"`
tag |
+| `*int`, `*string`, etc. | No | Pointer to primitives
excluded |
+| Primitives | No | Value types
|
+| `time.Time`, `time.Duration` | No | Value types
|
+| Arrays (`[N]T`) | No | Value types
|
+
+## Per-Field Reference Control
+
+By default, reference tracking is **disabled** for individual fields even when
global `WithTrackRef(true)` is set. You can enable reference tracking for
specific fields using the `ref` struct tag:
+
+```go
+type Container struct {
+ // Enable ref tracking for this field
+ SharedData *Data `fory:"ref"`
+
+ // Explicitly disable ref tracking (same as default)
+ SimpleData *Data `fory:"ref=false"`
+}
+```
+
+**Important notes**:
+
+- Per-field tags only take effect when global `WithTrackRef(true)` is set
+- When global `WithTrackRef(false)` (default), all field ref tags are ignored
+- Applies to slices, maps, and pointer to struct fields
+- Pointer to primitive types (e.g., `*int`, `*string`) cannot use this tag
+- Default is `ref=false` (no reference tracking per field)
+
+See [Struct Tags](struct-tags) for more details.
+
+## Circular References
+
+Reference tracking is required for circular data structures:
+
+### Circular Linked List
+
+```go
+type Node struct {
+ Value int32
+ Next *Node `fory:"ref"`
+}
+
+f := fory.New(fory.WithTrackRef(true))
+f.RegisterStruct(Node{}, 1)
+
+// Create circular list
+n1 := &Node{Value: 1}
+n2 := &Node{Value: 2}
+n3 := &Node{Value: 3}
+n1.Next = n2
+n2.Next = n3
+n3.Next = n1 // Circular reference back to n1
+
+data, _ := f.Serialize(n1)
+
+var result Node
+f.Deserialize(data, &result)
+// Circular structure is preserved
+// result.Next.Next.Next == &result
+```
+
+### Parent-Child Tree
+
+```go
+type TreeNode struct {
+ Value string
+ Parent *TreeNode `fory:"ref"`
+ Children []*TreeNode `fory:"ref"`
+}
+
+f := fory.New(fory.WithTrackRef(true))
+f.RegisterStruct(TreeNode{}, 1)
+
+root := &TreeNode{Value: "root"}
+child1 := &TreeNode{Value: "child1", Parent: root}
+child2 := &TreeNode{Value: "child2", Parent: root}
+root.Children = []*TreeNode{child1, child2}
+
+data, _ := f.Serialize(root)
+
+var result TreeNode
+f.Deserialize(data, &result)
+// result.Children[0].Parent == &result
+```
+
+### Graph Structures
+
+```go
+type GraphNode struct {
+ ID int32
+ Neighbors []*GraphNode `fory:"ref"`
+}
+
+f := fory.New(fory.WithTrackRef(true))
+f.RegisterStruct(GraphNode{}, 1)
+
+// Create a graph
+a := &GraphNode{ID: 1}
+b := &GraphNode{ID: 2}
+c := &GraphNode{ID: 3}
+
+// Bidirectional connections
+a.Neighbors = []*GraphNode{b, c}
+b.Neighbors = []*GraphNode{a, c}
+c.Neighbors = []*GraphNode{a, b}
+
+data, _ := f.Serialize(a)
+
+var result GraphNode
+f.Deserialize(data, &result)
+```
+
+## Shared Object Deduplication
+
+Reference tracking also deduplicates shared objects:
+
+```go
+type Config struct {
+ Setting string
+}
+
+type Application struct {
+ MainConfig *Config `fory:"ref"`
+ BackupConfig *Config `fory:"ref"`
+ FallbackConfig *Config `fory:"ref"`
+}
+
+f := fory.New(fory.WithTrackRef(true))
+f.RegisterStruct(Config{}, 1)
+f.RegisterStruct(Application{}, 2)
+
+// Shared configuration
+config := &Config{Setting: "value"}
+
+// Multiple references to same object
+app := &Application{
+ MainConfig: config,
+ BackupConfig: config,
+ FallbackConfig: config,
+}
+
+data, _ := f.Serialize(app)
+// 'config' serialized once, others are references
+
+var result Application
+f.Deserialize(data, &result)
+// result.MainConfig == result.BackupConfig == result.FallbackConfig
+```
+
+## Performance Considerations
+
+### Overhead
+
+Reference tracking adds overhead:
+
+- Memory for tracking seen objects (hash map)
+- Hash lookups during serialization
+- Additional bytes for reference flags and IDs
+
+### When to Enable
+
+**Enable reference tracking when**:
+
+- Data has circular references
+- Same object referenced multiple times
+- Serializing graph structures
+- Object identity must be preserved
+
+**Disable reference tracking when**:
+
+- Data is tree-structured (no cycles)
+- Each object appears only once
+- Maximum performance is required
+- Object identity doesn't matter
+
+### Memory Usage
+
+Reference tracking maintains a map of serializing objects:
+
+```go
+// Internal reference tracking structure
+type RefResolver struct {
+ writtenObjects map[refKey]int32 // pointer -> reference ID
+ readObjects []reflect.Value // reference ID -> object
+}
+```
+
+For large object graphs, this may increase memory usage.
+
+## Error Handling
+
+### Without Reference Tracking
+
+Circular references without tracking cause stack overflow or max depth errors:
+
+```go
+f := fory.New() // No reference tracking
+
+n1 := &Node{Value: 1}
+n1.Next = n1 // Self-reference
+
+data, err := f.Serialize(n1)
+// Error: max depth exceeded (or stack overflow)
+```
+
+### Invalid Reference ID
+
+During deserialization, an invalid reference ID produces an error:
+
+```go
+// Error type: ErrKindInvalidRefId
+```
+
+This occurs when serialized data contains a reference to an object that wasn't
previously serialized.
+
+## Complete Example
+
+```go
+package main
+
+import (
+ "fmt"
+ "github.com/apache/fory/go/fory"
+)
+
+type Person struct {
+ Name string
+ Friends []*Person `fory:"ref"`
+ BestFriend *Person `fory:"ref"`
+}
+
+func main() {
+ f := fory.New(fory.WithTrackRef(true))
+ f.RegisterStruct(Person{}, 1)
+
+ // Create people with mutual friendships
+ alice := &Person{Name: "Alice"}
+ bob := &Person{Name: "Bob"}
+ charlie := &Person{Name: "Charlie"}
+
+ alice.Friends = []*Person{bob, charlie}
+ alice.BestFriend = bob
+
+ bob.Friends = []*Person{alice, charlie}
+ bob.BestFriend = alice // Mutual best friends
+
+ charlie.Friends = []*Person{alice, bob}
+
+ // Serialize
+ data, err := f.Serialize(alice)
+ if err != nil {
+ panic(err)
+ }
+ fmt.Printf("Serialized %d bytes\n", len(data))
+
+ // Deserialize
+ var result Person
+ if err := f.Deserialize(data, &result); err != nil {
+ panic(err)
+ }
+
+ // Verify circular references preserved
+ fmt.Printf("Alice's best friend: %s\n", result.BestFriend.Name)
+ fmt.Printf("Bob's best friend: %s\n", result.BestFriend.BestFriend.Name)
+ // Output: Alice (circular reference preserved)
+}
+```
+
+## Related Topics
+
+- [Configuration](configuration)
+- [Struct Tags](struct-tags)
+- [Cross-Language Serialization](cross-language)
diff --git a/docs/docs/guide/go/schema-evolution.md
b/docs/docs/guide/go/schema-evolution.md
new file mode 100644
index 000000000..5624e8104
--- /dev/null
+++ b/docs/docs/guide/go/schema-evolution.md
@@ -0,0 +1,340 @@
+---
+title: Schema Evolution
+sidebar_position: 70
+id: go_schema_evolution
+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
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+---
+
+Schema evolution allows your data structures to change over time while
maintaining compatibility with previously serialized data. Fory Go supports
this through compatible mode.
+
+## Enabling Compatible Mode
+
+Enable compatible mode when creating a Fory instance:
+
+```go
+f := fory.New(fory.WithCompatible(true))
+```
+
+## How It Works
+
+### Without Compatible Mode (Default)
+
+- Compact serialization without metadata
+- Struct hash is checked during deserialization
+- Any schema change causes `ErrKindHashMismatch`
+
+### With Compatible Mode
+
+- Type metadata is written to serialized data
+- Supports adding, removing, and reordering fields
+- Enables forward and backward compatibility
+
+## Supported Schema Changes
+
+### Adding Fields
+
+New fields can be added; they receive zero values when deserializing old data:
+
+```go
+// Version 1
+type UserV1 struct {
+ ID int64
+ Name string
+}
+
+// Version 2 (added Email)
+type UserV2 struct {
+ ID int64
+ Name string
+ Email string // New field
+}
+
+f := fory.New(fory.WithCompatible(true))
+f.RegisterStruct(UserV1{}, 1)
+
+// Serialize with V1
+userV1 := &UserV1{ID: 1, Name: "Alice"}
+data, _ := f.Serialize(userV1)
+
+// Deserialize with V2
+f2 := fory.New(fory.WithCompatible(true))
+f2.RegisterStruct(UserV2{}, 1)
+
+var userV2 UserV2
+f2.Deserialize(data, &userV2)
+// userV2.Email = "" (zero value)
+```
+
+### Removing Fields
+
+Removed fields are skipped during deserialization:
+
+```go
+// Version 1
+type ConfigV1 struct {
+ Host string
+ Port int32
+ Timeout int64
+ Debug bool // Will be removed
+}
+
+// Version 2 (removed Debug)
+type ConfigV2 struct {
+ Host string
+ Port int32
+ Timeout int64
+ // Debug field removed
+}
+
+f := fory.New(fory.WithCompatible(true))
+f.RegisterStruct(ConfigV1{}, 1)
+
+// Serialize with V1
+config := &ConfigV1{Host: "localhost", Port: 8080, Timeout: 30, Debug: true}
+data, _ := f.Serialize(config)
+
+// Deserialize with V2
+f2 := fory.New(fory.WithCompatible(true))
+f2.RegisterStruct(ConfigV2{}, 1)
+
+var configV2 ConfigV2
+f2.Deserialize(data, &configV2)
+// Debug field data is skipped
+```
+
+### Reordering Fields
+
+Field order can change between versions:
+
+```go
+// Version 1
+type PersonV1 struct {
+ FirstName string
+ LastName string
+ Age int32
+}
+
+// Version 2 (reordered)
+type PersonV2 struct {
+ Age int32 // Moved up
+ LastName string
+ FirstName string // Moved down
+}
+```
+
+Compatible mode handles this automatically by matching fields by name.
+
+## Incompatible Changes
+
+Some changes are NOT supported, even in compatible mode:
+
+### Type Changes
+
+```go
+// NOT SUPPORTED
+type V1 struct {
+ Value int32 // int32
+}
+
+type V2 struct {
+ Value string // Changed to string - INCOMPATIBLE
+}
+```
+
+### Renaming Fields
+
+```go
+// NOT SUPPORTED (treated as remove + add)
+type V1 struct {
+ UserName string
+}
+
+type V2 struct {
+ Username string // Different name - NOT a rename
+}
+```
+
+This is treated as removing `UserName` and adding `Username`, resulting in
data loss.
+
+## Best Practices
+
+### 1. Use Compatible Mode for Persistent Data
+
+```go
+// For data stored in databases, files, or caches
+f := fory.New(fory.WithCompatible(true))
+```
+
+### 2. Provide Default Values
+
+```go
+type ConfigV2 struct {
+ Host string
+ Port int32
+ Timeout int64
+ Retries int32 // New field
+}
+
+func NewConfigV2() *ConfigV2 {
+ return &ConfigV2{
+ Retries: 3, // Default value
+ }
+}
+
+// After deserialize, apply defaults
+if config.Retries == 0 {
+ config.Retries = 3
+}
+```
+
+## Cross-Language Schema Evolution
+
+Schema evolution works across languages:
+
+### Go (Producer)
+
+```go
+type MessageV1 struct {
+ ID int64
+ Content string
+}
+
+f := fory.New(fory.WithCompatible(true))
+f.RegisterStruct(MessageV1{}, 1)
+data, _ := f.Serialize(&MessageV1{ID: 1, Content: "Hello"})
+```
+
+### Java (Consumer with newer schema)
+
+```java
+public class Message {
+ long id;
+ String content;
+ String author; // New field in Java
+}
+
+Fory fory = Fory.builder()
+ .withXlang(true)
+ .withCompatibleMode(true)
+ .build();
+fory.register(Message.class, 1);
+Message msg = fory.deserialize(data, Message.class);
+// msg.author will be null
+```
+
+## Performance Considerations
+
+Compatible mode mainly affects serialized size:
+
+| Aspect | Schema Consistent | Compatible Mode
|
+| ------------------ | ----------------- |
-------------------------------------------------------- |
+| Serialized Size | Smaller | Larger (includes metadata,
especially without field IDs) |
+| Speed | Fast | Similar (metadata is just memcpy)
|
+| Schema Flexibility | None | Full
|
+
+**Note**: Using field IDs (`fory:"id=N"`) reduces metadata size in compatible
mode.
+
+**Recommendation**: Use compatible mode for:
+
+- Persistent storage
+- Cross-service communication
+- Long-lived caches
+
+Use schema consistent mode for:
+
+- In-memory operations
+- Same-version communication
+- Minimum serialized size
+
+## Error Handling
+
+### Hash Mismatch (Schema Consistent Mode)
+
+```go
+f := fory.New() // Compatible mode disabled
+
+// Schema changed without compatible mode
+err := f.Deserialize(oldData, &newStruct)
+// Error: ErrKindHashMismatch
+```
+
+### Unknown Fields
+
+In compatible mode, unknown fields are skipped silently. To detect them:
+
+```go
+// Currently, Fory skips unknown fields automatically
+// No explicit API for detecting unknown fields
+```
+
+## Complete Example
+
+```go
+package main
+
+import (
+ "fmt"
+ "github.com/apache/fory/go/fory"
+)
+
+// V1: Initial schema
+type ProductV1 struct {
+ ID int64
+ Name string
+ Price float64
+}
+
+// V2: Added fields
+type ProductV2 struct {
+ ID int64
+ Name string
+ Price float64
+ Description string // New
+ InStock bool // New
+}
+
+func main() {
+ // Serialize with V1
+ f1 := fory.New(fory.WithCompatible(true))
+ f1.RegisterStruct(ProductV1{}, 1)
+
+ product := &ProductV1{ID: 1, Name: "Widget", Price: 9.99}
+ data, _ := f1.Serialize(product)
+ fmt.Printf("V1 serialized: %d bytes\n", len(data))
+
+ // Deserialize with V2
+ f2 := fory.New(fory.WithCompatible(true))
+ f2.RegisterStruct(ProductV2{}, 1)
+
+ var productV2 ProductV2
+ if err := f2.Deserialize(data, &productV2); err != nil {
+ panic(err)
+ }
+
+ fmt.Printf("ID: %d\n", productV2.ID)
+ fmt.Printf("Name: %s\n", productV2.Name)
+ fmt.Printf("Price: %.2f\n", productV2.Price)
+ fmt.Printf("Description: %q (zero value)\n", productV2.Description)
+ fmt.Printf("InStock: %v (zero value)\n", productV2.InStock)
+}
+```
+
+## Related Topics
+
+- [Configuration](configuration)
+- [Cross-Language Serialization](cross-language)
+- [Troubleshooting](troubleshooting)
diff --git a/docs/docs/guide/go/struct-tags.md
b/docs/docs/guide/go/struct-tags.md
new file mode 100644
index 000000000..6075848ef
--- /dev/null
+++ b/docs/docs/guide/go/struct-tags.md
@@ -0,0 +1,335 @@
+---
+title: Struct Tags
+sidebar_position: 60
+id: go_struct_tags
+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
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+---
+
+Fory Go uses struct tags to customize field-level serialization behavior. This
allows fine-grained control over how individual fields are serialized.
+
+## Tag Syntax
+
+The general syntax for Fory struct tags:
+
+```go
+type MyStruct struct {
+ Field Type `fory:"option1,option2=value"`
+}
+```
+
+Multiple options are separated by commas (`,`).
+
+## Available Tags
+
+### Field ID
+
+Use `id=N` to assign a numeric ID to a field for compact encoding:
+
+```go
+type User struct {
+ ID int64 `fory:"id=0"`
+ Name string `fory:"id=1"`
+ Age int32 `fory:"id=2"`
+}
+```
+
+**Benefits**:
+
+- Smaller serialized size (numeric IDs vs field names)
+- Faster serialization/deserialization
+- Required for optimal cross-language compatibility
+
+**Notes**:
+
+- IDs must be unique within a struct
+- IDs must be >= 0
+- If not specified, field name is used (larger payload)
+
+### Ignoring Fields
+
+Use `-` to exclude a field from serialization:
+
+```go
+type User struct {
+ ID int64
+ Name string
+ Password string `fory:"-"` // Not serialized
+}
+```
+
+The `Password` field will not be included in serialized output and will remain
at its zero value after deserialization.
+
+### Nullable
+
+Use `nullable` to control whether null flags are written for pointer fields:
+
+```go
+type Record struct {
+ // Write null flag for this field (allows nil values)
+ OptionalData *Data `fory:"nullable"`
+
+ // Skip null flag (field must not be nil)
+ RequiredData *Data `fory:"nullable=false"`
+}
+```
+
+**Notes**:
+
+- Only applies to pointer, slice, and map fields
+- When `nullable=false`, serializing a nil value will cause an error
+- Default is `false` (no null flag written)
+
+### Reference Tracking
+
+Control per-field reference tracking for slices, maps, or pointer to struct
fields:
+
+```go
+type Container struct {
+ // Enable reference tracking for this field
+ SharedData *Data `fory:"ref"`
+
+ // Disable reference tracking for this field
+ SimpleData *Data `fory:"ref=false"`
+}
+```
+
+**Notes**:
+
+- Applies to slices, maps, and pointer to struct fields
+- Pointer to primitive types (e.g., `*int`, `*string`) cannot use this tag
+- Default is `ref=false` (no reference tracking)
+- When global `WithTrackRef(false)` is set, field ref tags are ignored
+- When global `WithTrackRef(true)` is set, use `ref=false` to disable for
specific fields
+
+**Use cases**:
+
+- Enable for fields that may be circular or shared
+- Disable for fields that are always unique (optimization)
+
+### Encoding
+
+Use `encoding` to control how numeric fields are encoded:
+
+```go
+type Metrics struct {
+ // Variable-length encoding (default, smaller for small values)
+ Count int64 `fory:"encoding=varint"`
+
+ // Fixed-length encoding (consistent size)
+ Timestamp int64 `fory:"encoding=fixed"`
+
+ // Tagged encoding (includes type tag)
+ Value int64 `fory:"encoding=tagged"`
+}
+```
+
+**Supported encodings**:
+
+| Type | Options | Default |
+| -------- | --------------------------- | -------- |
+| `int32` | `varint`, `fixed` | `varint` |
+| `uint32` | `varint`, `fixed` | `varint` |
+| `int64` | `varint`, `fixed`, `tagged` | `varint` |
+| `uint64` | `varint`, `fixed`, `tagged` | `varint` |
+
+**When to use**:
+
+- `varint`: Best for values that are often small (default)
+- `fixed`: Best for values that use full range (e.g., timestamps, hashes)
+- `tagged`: When type information needs to be preserved
+
+**Shorthand for int32/uint32**:
+
+Use `compress` as a convenience tag for int32/uint32 fields:
+
+```go
+type Data struct {
+ SmallValue int32 `fory:"compress"` // Same as encoding=varint
(default)
+ FixedValue uint32 `fory:"compress=false"` // Same as encoding=fixed
+}
+```
+
+## Combining Tags
+
+Multiple tags can be combined using comma separator:
+
+```go
+type Document struct {
+ ID int64 `fory:"id=0,encoding=fixed"`
+ Content string `fory:"id=1"`
+ Author *User `fory:"id=2,ref"`
+}
+```
+
+## Integration with Other Tags
+
+Fory tags coexist with other struct tags:
+
+```go
+type User struct {
+ ID int64 `json:"id" fory:"id=0"`
+ Name string `json:"name,omitempty" fory:"id=1"`
+ Password string `json:"-" fory:"-"`
+}
+```
+
+Each tag namespace is independent.
+
+## Field Visibility
+
+Only **exported fields** (starting with uppercase) are considered:
+
+```go
+type User struct {
+ ID int64 // Serialized
+ Name string // Serialized
+ password string // NOT serialized (unexported, no tag needed)
+}
+```
+
+Unexported fields are always ignored, regardless of tags.
+
+## Field Ordering
+
+Fields are serialized in a consistent order based on:
+
+1. Field name (alphabetically in snake_case)
+2. Field type
+
+This ensures cross-language compatibility where field order matters.
+
+## Struct Hash
+
+Fory computes a hash of struct fields for version checking:
+
+- Hash includes field names and types
+- Hash is written to serialized data
+- Mismatch triggers `ErrKindHashMismatch`
+
+Struct field changes affect the hash:
+
+```go
+// These produce different hashes
+type V1 struct {
+ UserID int64
+}
+
+type V2 struct {
+ UserId int64 // Different field name = different hash
+}
+```
+
+## Examples
+
+### API Response Struct
+
+```go
+type APIResponse struct {
+ Status int32 `json:"status" fory:"id=0"`
+ Message string `json:"message" fory:"id=1"`
+ Data any `json:"data" fory:"id=2"`
+ Internal string `json:"-" fory:"-"` // Ignored in both JSON and Fory
+}
+```
+
+### Caching with Shared References
+
+```go
+type CacheEntry struct {
+ Key string
+ Value *CachedData `fory:"ref"` // May be shared
+ Metadata *Metadata `fory:"ref=false"` // Always unique
+ ExpiresAt int64
+}
+```
+
+### Document with Circular References
+
+```go
+type Document struct {
+ ID int64
+ Title string
+ Parent *Document `fory:"ref"` // May reference self or siblings
+ Children []*Document `fory:"ref"`
+}
+```
+
+## Tag Parsing Errors
+
+Invalid tags produce errors during registration:
+
+```go
+type BadStruct struct {
+ Field int `fory:"invalid=option=format"`
+}
+
+f := fory.New()
+err := f.RegisterStruct(BadStruct{}, 1)
+// Error: ErrKindInvalidTag
+```
+
+## Best Practices
+
+1. **Use `-` for sensitive data**: Passwords, tokens, internal state
+2. **Enable ref tracking for shared objects**: When the same pointer appears
multiple times
+3. **Disable ref tracking for simple fields**: Optimization when you know the
field is unique
+4. **Keep names consistent**: Cross-language names should match
+5. **Document tag usage**: Especially for non-obvious configurations
+
+## Common Patterns
+
+### Ignoring Computed Fields
+
+```go
+type Rectangle struct {
+ Width float64
+ Height float64
+ Area float64 `fory:"-"` // Computed, don't serialize
+}
+
+func (r *Rectangle) ComputeArea() {
+ r.Area = r.Width * r.Height
+}
+```
+
+### Circular Structure with Parent
+
+```go
+type TreeNode struct {
+ Value string
+ Parent *TreeNode `fory:"ref"` // Circular back-reference
+ Children []*TreeNode `fory:"ref"`
+}
+```
+
+### Mixed Serialization Needs
+
+```go
+type Session struct {
+ ID string
+ UserID int64
+ Token string `fory:"-"` // Security: don't serialize
+ User *User `fory:"ref"` // May be shared across sessions
+ CreatedAt int64
+}
+```
+
+## Related Topics
+
+- [References](references)
+- [Basic Serialization](basic-serialization)
+- [Schema Evolution](schema-evolution)
diff --git a/docs/docs/guide/go/supported-types.md
b/docs/docs/guide/go/supported-types.md
new file mode 100644
index 000000000..5b68d50c7
--- /dev/null
+++ b/docs/docs/guide/go/supported-types.md
@@ -0,0 +1,369 @@
+---
+title: Supported Types
+sidebar_position: 40
+id: go_supported_types
+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
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+---
+
+Fory Go supports a wide range of Go types for serialization. This guide covers
all supported types and their cross-language mappings.
+
+## Primitive Types
+
+| Go Type | Fory TypeId | Encoding | Notes
|
+| ---------------- | ------------ | --------------------- |
--------------------------------- |
+| `bool` | BOOL (1) | 1 byte |
|
+| `int8` | INT8 (2) | 1 byte, signed |
|
+| `int16` | INT16 (3) | 2 bytes, signed | Little-endian
|
+| `int32` | INT32 (4) | Varint | Variable-length
encoding |
+| `int64` | INT64 (6) | Varint | Variable-length
encoding |
+| `int` | INT32/INT64 | Varint | Platform-dependent
(32 or 64 bit) |
+| `uint8` / `byte` | UINT8 (9) | 1 byte, unsigned |
|
+| `uint16` | UINT16 (10) | 2 bytes, unsigned | Little-endian
|
+| `uint32` | UINT32 (11) | Varuint | Variable-length
encoding |
+| `uint64` | UINT64 (13) | Varuint | Variable-length
encoding |
+| `float32` | FLOAT32 (17) | 4 bytes | IEEE 754
|
+| `float64` | FLOAT64 (18) | 8 bytes | IEEE 754
|
+| `string` | STRING (19) | Length-prefixed UTF-8 |
|
+
+### Integer Encoding
+
+Fory uses variable-length integer encoding (varint) for better compression:
+
+- Small values use fewer bytes
+- Negative values use ZigZag encoding
+- Platform `int` maps to `int32` on 32-bit, `int64` on 64-bit systems
+
+```go
+f := fory.New()
+
+// All integer types supported
+var i8 int8 = 127
+var i16 int16 = 32767
+var i32 int32 = 2147483647
+var i64 int64 = 9223372036854775807
+
+data, _ := f.Serialize(i64) // Uses varint encoding
+```
+
+## Collection Types
+
+### Slices
+
+| Go Type | Fory TypeId | Notes |
+| --------------- | ------------- | --------------------- |
+| `[]bool` | BOOL_ARRAY | Optimized encoding |
+| `[]int8` | INT8_ARRAY | Optimized encoding |
+| `[]int16` | INT16_ARRAY | Optimized encoding |
+| `[]int32` | INT32_ARRAY | Optimized encoding |
+| `[]int64` | INT64_ARRAY | Optimized encoding |
+| `[]float32` | FLOAT32_ARRAY | Optimized encoding |
+| `[]float64` | FLOAT64_ARRAY | Optimized encoding |
+| `[]string` | LIST | Generic list encoding |
+| `[]T` (any) | LIST (20) | Any serializable type |
+| `[]I` (any/any) | LIST | Any interface type |
+
+```go
+f := fory.New()
+
+// Primitive slices (optimized)
+ints := []int32{1, 2, 3, 4, 5}
+data, _ := f.Serialize(ints)
+
+// String slices
+strs := []string{"a", "b", "c"}
+data, _ = f.Serialize(strs)
+
+// Struct slices
+users := []User{{ID: 1}, {ID: 2}}
+data, _ = f.Serialize(users)
+
+// Dynamic slices
+dynamic := []any{1, "hello", true}
+data, _ = f.Serialize(dynamic)
+```
+
+### Maps
+
+| Go Type | Fory TypeId | Notes |
+| -------------------- | ----------- | ----------------------- |
+| `map[string]string` | MAP (22) | Optimized |
+| `map[string]int64` | MAP | Optimized |
+| `map[string]int32` | MAP | Optimized |
+| `map[string]int` | MAP | Optimized |
+| `map[string]float64` | MAP | Optimized |
+| `map[string]bool` | MAP | Optimized |
+| `map[int32]int32` | MAP | Optimized |
+| `map[int64]int64` | MAP | Optimized |
+| `map[int]int` | MAP | Optimized |
+| `map[string]any` | MAP | Dynamic values |
+| `map[any]any` | MAP | Dynamic keys and values |
+
+```go
+f := fory.New()
+
+// String key maps
+m1 := map[string]string{"key": "value"}
+m2 := map[string]int64{"count": 42}
+
+// Integer key maps
+m3 := map[int32]int32{1: 100, 2: 200}
+
+// Dynamic maps
+m4 := map[string]any{
+ "name": "Alice",
+ "age": int64(30),
+}
+```
+
+### Sets
+
+Fory provides a generic `Set[T]` type (uses `map[T]struct{}` for zero memory
overhead):
+
+```go
+// Create a set of strings
+s := fory.NewSet[string]()
+s.Add("a", "b", "c")
+
+// Check membership
+if s.Contains("a") {
+ fmt.Println("found")
+}
+
+// Serialize
+data, _ := f.Serialize(s)
+```
+
+## Time Types
+
+| Go Type | Fory TypeId | Notes |
+| --------------- | -------------- | -------------------- |
+| `time.Time` | TIMESTAMP (34) | Nanosecond precision |
+| `time.Duration` | DURATION (33) | Nanosecond precision |
+
+```go
+import "time"
+
+f := fory.New()
+
+// Timestamp
+t := time.Now()
+data, _ := f.Serialize(t)
+
+// Duration
+d := 5 * time.Second
+data, _ = f.Serialize(d)
+```
+
+## Struct Types
+
+| Category | Fory TypeId | Notes
|
+| ----------------------- | ---------------------------- |
-------------------------------- |
+| Struct | STRUCT (25) | Registered by ID,
no evolution |
+| Compatible Struct | COMPATIBLE_STRUCT (26) | With schema
evolution |
+| Named Struct | NAMED_STRUCT (27) | Registered by name,
no evolution |
+| Named Compatible Struct | NAMED_COMPATIBLE_STRUCT (28) | Named with schema
evolution |
+
+### Struct Requirements
+
+1. **Exported fields only**: Fields starting with uppercase are serialized
+2. **Supported field types**: All types listed in this document
+3. **Registration**: Structs should be registered for cross-language use
+
+```go
+type User struct {
+ ID int64 // Serialized
+ Name string // Serialized
+ Age int32 // Serialized
+ password string // NOT serialized (unexported)
+}
+
+f := fory.New()
+f.RegisterStruct(User{}, 1)
+
+user := &User{ID: 1, Name: "Alice", Age: 30, password: "secret"}
+data, _ := f.Serialize(user)
+```
+
+### Nested Structs
+
+```go
+type Address struct {
+ Street string
+ City string
+ Country string
+}
+
+type Company struct {
+ Name string
+ Address Address
+ Founded int32
+}
+
+f := fory.New()
+f.RegisterStruct(Address{}, 1)
+f.RegisterStruct(Company{}, 2)
+```
+
+## Pointer Types
+
+| Go Type | Behavior |
+| ------- | ---------------------------------------- |
+| `*T` | Nil-able, reference tracked (if enabled) |
+| `**T` | Nested pointers supported |
+
+```go
+f := fory.New(fory.WithTrackRef(true))
+
+type Node struct {
+ Value int32
+ Left *Node
+ Right *Node
+}
+
+f.RegisterStruct(Node{}, 1)
+
+root := &Node{
+ Value: 1,
+ Left: &Node{Value: 2},
+ Right: &Node{Value: 3},
+}
+
+data, _ := f.Serialize(root)
+```
+
+### Nil Handling
+
+```go
+var ptr *User = nil
+data, _ := f.Serialize(ptr)
+
+var result *User
+f.Deserialize(data, &result)
+// result == nil
+```
+
+## Interface Types
+
+| Go Type | Fory TypeId | Notes |
+| ------- | ----------- | ------------------ |
+| `any` | UNION (31) | Polymorphic values |
+
+```go
+f := fory.New()
+
+// Serialize any
+var value any = "hello"
+data, _ := f.Serialize(value)
+
+var result any
+f.Deserialize(data, &result)
+// result = "hello" (string)
+```
+
+For struct interfaces, register all possible concrete types:
+
+```go
+type Shape interface {
+ Area() float64
+}
+
+type Circle struct {
+ Radius float64
+}
+
+func (c Circle) Area() float64 {
+ return 3.14159 * c.Radius * c.Radius
+}
+
+f := fory.New()
+f.RegisterStruct(Circle{}, 1)
+
+var shape Shape = Circle{Radius: 5.0}
+data, _ := f.Serialize(shape)
+```
+
+## Binary Data
+
+| Go Type | Fory TypeId | Notes |
+| -------- | ----------- | --------------------- |
+| `[]byte` | BINARY (37) | Variable-length bytes |
+
+```go
+f := fory.New()
+
+data := []byte{0x01, 0x02, 0x03, 0x04}
+serialized, _ := f.Serialize(data)
+
+var result []byte
+f.Deserialize(serialized, &result)
+```
+
+## Enum Types
+
+Go uses integer types for enums:
+
+```go
+type Status int32
+
+const (
+ StatusPending Status = 0
+ StatusActive Status = 1
+ StatusComplete Status = 2
+)
+
+f := fory.New()
+f.RegisterEnum(Status(0), 1)
+
+status := StatusActive
+data, _ := f.Serialize(status)
+```
+
+## Cross-Language Type Mapping
+
+| Go Type | Java | Python | C++ | Rust |
+| --------------- | -------- | --------- | ------------------ | ------------ |
+| `bool` | boolean | bool | bool | bool |
+| `int8` | byte | int | int8_t | i8 |
+| `int16` | short | int | int16_t | i16 |
+| `int32` | int | int | int32_t | i32 |
+| `int64` | long | int | int64_t | i64 |
+| `float32` | float | float | float | f32 |
+| `float64` | double | float | double | f64 |
+| `string` | String | str | std::string | String |
+| `[]T` | List<T> | list | std::vector<T> | Vec<T> |
+| `map[K]V` | Map<K,V> | dict | std::unordered_map | HashMap<K,V> |
+| `time.Time` | Instant | datetime | - | - |
+| `time.Duration` | Duration | timedelta | - | - |
+
+See [Cross-Language Serialization](cross-language) for detailed mapping.
+
+## Unsupported Types
+
+The following Go types are **not supported**:
+
+- Channels (`chan T`)
+- Functions (`func()`)
+- Complex numbers (`complex64`, `complex128`)
+- Unsafe pointers (`unsafe.Pointer`)
+
+Attempting to serialize these types will result in an error.
+
+## Related Topics
+
+- [Type Registration](type-registration)
+- [Cross-Language Serialization](cross-language)
+- [References](references)
diff --git a/docs/docs/guide/go/thread-safety.md
b/docs/docs/guide/go/thread-safety.md
new file mode 100644
index 000000000..1f475b3a1
--- /dev/null
+++ b/docs/docs/guide/go/thread-safety.md
@@ -0,0 +1,347 @@
+---
+title: Thread Safety
+sidebar_position: 100
+id: go_thread_safety
+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
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+---
+
+This guide covers concurrent usage patterns for Fory Go, including the
thread-safe wrapper and best practices for multi-goroutine environments.
+
+## Default Fory Instance
+
+The default `Fory` instance is **not thread-safe**:
+
+```go
+f := fory.New()
+
+// NOT SAFE: Concurrent access from multiple goroutines
+go func() {
+ f.Serialize(value1) // Race condition!
+}()
+go func() {
+ f.Serialize(value2) // Race condition!
+}()
+```
+
+### Why Not Thread-Safe?
+
+For performance, Fory reuses internal state:
+
+- Buffer is cleared and reused between calls
+- Reference resolvers are reset
+- Context objects are recycled
+
+This avoids allocations but requires exclusive access.
+
+## Thread-Safe Wrapper
+
+For concurrent use, use the `threadsafe` package:
+
+```go
+import "github.com/apache/fory/go/fory/threadsafe"
+
+// Create thread-safe Fory
+f := threadsafe.New()
+
+// Safe for concurrent use
+go func() {
+ data, _ := f.Serialize(value1)
+}()
+go func() {
+ data, _ := f.Serialize(value2)
+}()
+```
+
+### How It Works
+
+The thread-safe wrapper uses `sync.Pool`:
+
+1. **Acquire**: Gets a Fory instance from the pool
+2. **Use**: Performs serialization/deserialization
+3. **Copy**: Copies result data (buffer will be reused)
+4. **Release**: Returns instance to pool
+
+```go
+// Simplified implementation
+func (f *Fory) Serialize(v any) ([]byte, error) {
+ fory := f.pool.Get().(*fory.Fory)
+ defer f.pool.Put(fory)
+
+ data, err := fory.Serialize(v)
+ if err != nil {
+ return nil, err
+ }
+
+ // Copy because underlying buffer will be reused
+ result := make([]byte, len(data))
+ copy(result, data)
+ return result, nil
+}
+```
+
+### API
+
+```go
+// Create thread-safe instance
+f := threadsafe.New()
+
+// Instance methods
+data, err := f.Serialize(value)
+err = f.Deserialize(data, &target)
+
+// Generic functions
+data, err := threadsafe.Serialize(f, &value)
+err = threadsafe.Deserialize(f, data, &target)
+
+// Global convenience functions
+data, err := threadsafe.Marshal(&value)
+err = threadsafe.Unmarshal(data, &target)
+```
+
+## Type Registration
+
+Type registration should be done before concurrent use:
+
+```go
+f := threadsafe.New()
+
+// Register types BEFORE concurrent access
+f.RegisterStruct(User{}, 1)
+f.RegisterStruct(Order{}, 2)
+
+// Now safe to use concurrently
+go func() {
+ f.Serialize(&User{ID: 1})
+}()
+```
+
+### Thread-Safe Registration
+
+The thread-safe wrapper handles registration safely:
+
+```go
+// Safe: Registration is synchronized
+f := threadsafe.New()
+f.RegisterStruct(User{}, 1) // Thread-safe
+```
+
+However, for best performance, register all types at startup before concurrent
use.
+
+## Zero-Copy Considerations
+
+### Non-Thread-Safe Instance
+
+With the default Fory, returned byte slices are views into the internal buffer:
+
+```go
+f := fory.New()
+
+data1, _ := f.Serialize(value1)
+// data1 is valid
+
+data2, _ := f.Serialize(value2)
+// data1 is NOW INVALID (buffer was reused)
+```
+
+### Thread-Safe Instance
+
+The thread-safe wrapper copies data automatically:
+
+```go
+f := threadsafe.New()
+
+data1, _ := f.Serialize(value1)
+data2, _ := f.Serialize(value2)
+// Both data1 and data2 are valid (independent copies)
+```
+
+This is safer but has allocation overhead.
+
+## Performance Comparison
+
+| Scenario | Non-Thread-Safe | Thread-Safe |
+| ------------------- | --------------- | ---------------------- |
+| Single goroutine | Fastest | Slower (pool overhead) |
+| Multiple goroutines | Unsafe | Safe, good scaling |
+| Memory allocations | Minimal | Per-call copy |
+| Buffer reuse | Yes | Per-pool-instance |
+
+### Benchmarking
+
+```go
+func BenchmarkNonThreadSafe(b *testing.B) {
+ f := fory.New()
+ f.RegisterStruct(User{}, 1)
+ user := &User{ID: 1, Name: "Alice"}
+
+ for i := 0; i < b.N; i++ {
+ data, _ := f.Serialize(user)
+ _ = data
+ }
+}
+
+func BenchmarkThreadSafe(b *testing.B) {
+ f := threadsafe.New()
+ f.RegisterStruct(User{}, 1)
+ user := &User{ID: 1, Name: "Alice"}
+
+ for i := 0; i < b.N; i++ {
+ data, _ := f.Serialize(user)
+ _ = data
+ }
+}
+```
+
+## Patterns
+
+### Per-Goroutine Instance
+
+For maximum performance with known goroutine count:
+
+```go
+func worker(id int) {
+ // Each worker has its own Fory instance
+ f := fory.New()
+ f.RegisterStruct(User{}, 1)
+
+ for task := range tasks {
+ data, _ := f.Serialize(task)
+ process(data)
+ }
+}
+
+// Start workers
+for i := 0; i < numWorkers; i++ {
+ go worker(i)
+}
+```
+
+### Shared Thread-Safe Instance
+
+For dynamic goroutine count or simplicity:
+
+```go
+// Single shared instance
+var f = threadsafe.New()
+
+func init() {
+ f.RegisterStruct(User{}, 1)
+}
+
+func handleRequest(user *User) []byte {
+ // Safe from any goroutine
+ data, _ := f.Serialize(user)
+ return data
+}
+```
+
+### HTTP Handler Example
+
+```go
+var fory = threadsafe.New()
+
+func init() {
+ fory.RegisterStruct(Response{}, 1)
+}
+
+func handler(w http.ResponseWriter, r *http.Request) {
+ response := &Response{
+ Status: "ok",
+ Data: getData(),
+ }
+
+ // Safe: threadsafe.Fory handles concurrency
+ data, err := fory.Serialize(response)
+ if err != nil {
+ http.Error(w, err.Error(), 500)
+ return
+ }
+
+ w.Header().Set("Content-Type", "application/octet-stream")
+ w.Write(data)
+}
+```
+
+## Common Mistakes
+
+### Sharing Non-Thread-Safe Instance
+
+```go
+// WRONG: Race condition
+var f = fory.New()
+
+func handler1() {
+ f.Serialize(value1) // Race!
+}
+
+func handler2() {
+ f.Serialize(value2) // Race!
+}
+```
+
+**Fix**: Use `threadsafe.New()` or per-goroutine instances.
+
+### Keeping Reference to Buffer
+
+```go
+// WRONG: Buffer invalidated on next call
+f := fory.New()
+data, _ := f.Serialize(value1)
+savedData := data // Just copies the slice header!
+
+f.Serialize(value2) // Invalidates data and savedData
+```
+
+**Fix**: Clone the data or use thread-safe wrapper.
+
+```go
+// Correct: Clone the data
+data, _ := f.Serialize(value1)
+savedData := make([]byte, len(data))
+copy(savedData, data)
+
+// Or use thread-safe (auto-copies)
+f := threadsafe.New()
+data, _ := f.Serialize(value1) // Already copied
+```
+
+### Registering Types Concurrently
+
+```go
+// RISKY: Concurrent registration
+go func() {
+ f.RegisterStruct(TypeA{}, 1)
+}()
+go func() {
+ f.Serialize(value) // May not see TypeA
+}()
+```
+
+**Fix**: Register all types before concurrent use.
+
+## Best Practices
+
+1. **Register types at startup**: Before any concurrent operations
+2. **Clone data if keeping references**: With non-thread-safe instance
+3. **Use per-worker instances for hot paths**: Eliminates pool contention
+4. **Profile before optimizing**: Thread-safe overhead may be negligible
+
+## Related Topics
+
+- [Configuration](configuration)
+- [Basic Serialization](basic-serialization)
+- [Troubleshooting](troubleshooting)
diff --git a/docs/docs/guide/go/troubleshooting.md
b/docs/docs/guide/go/troubleshooting.md
new file mode 100644
index 000000000..f6cd38875
--- /dev/null
+++ b/docs/docs/guide/go/troubleshooting.md
@@ -0,0 +1,448 @@
+---
+title: Troubleshooting
+sidebar_position: 110
+id: go_troubleshooting
+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
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+---
+
+This guide covers common issues and solutions when using Fory Go.
+
+## Error Types
+
+Fory Go uses typed errors with specific error kinds:
+
+```go
+type Error struct {
+ kind ErrorKind
+ message string
+ // Additional context fields
+}
+
+func (e Error) Kind() ErrorKind { return e.kind }
+func (e Error) Error() string { return e.message }
+```
+
+### Error Kinds
+
+| Kind | Value | Description |
+| ------------------------------ | ----- | ------------------------------- |
+| `ErrKindOK` | 0 | No error |
+| `ErrKindBufferOutOfBound` | 1 | Read/write beyond buffer bounds |
+| `ErrKindTypeMismatch` | 2 | Type ID mismatch |
+| `ErrKindUnknownType` | 3 | Unknown type encountered |
+| `ErrKindSerializationFailed` | 4 | General serialization failure |
+| `ErrKindDeserializationFailed` | 5 | General deserialization failure |
+| `ErrKindMaxDepthExceeded` | 6 | Recursion depth limit exceeded |
+| `ErrKindNilPointer` | 7 | Unexpected nil pointer |
+| `ErrKindInvalidRefId` | 8 | Invalid reference ID |
+| `ErrKindHashMismatch` | 9 | Struct hash mismatch |
+| `ErrKindInvalidTag` | 10 | Invalid fory struct tag |
+
+## Common Errors and Solutions
+
+### ErrKindUnknownType
+
+**Error**: `unknown type encountered`
+
+**Cause**: Type not registered before serialization/deserialization.
+
+**Solution**:
+
+```go
+f := fory.New()
+
+// Register type before use
+f.RegisterStruct(User{}, 1)
+
+// Now serialization works
+data, _ := f.Serialize(&User{ID: 1})
+```
+
+### ErrKindTypeMismatch
+
+**Error**: `type mismatch: expected X, got Y`
+
+**Cause**: Serialized data has different type than expected.
+
+**Solutions**:
+
+1. **Use correct target type**:
+
+```go
+// Wrong: Deserializing User into Order
+var order Order
+f.Deserialize(userData, &order) // Error!
+
+// Correct
+var user User
+f.Deserialize(userData, &user)
+```
+
+2. **Ensure consistent registration**:
+
+```go
+// Serializer
+f1 := fory.New()
+f1.RegisterStruct(User{}, 1)
+
+// Deserializer - must use same ID
+f2 := fory.New()
+f2.RegisterStruct(User{}, 1) // Same ID!
+```
+
+### ErrKindHashMismatch
+
+**Error**: `hash X is not consistent with Y for type Z`
+
+**Cause**: Struct definition changed between serialization and deserialization.
+
+**Solutions**:
+
+1. **Enable compatible mode**:
+
+```go
+f := fory.New(fory.WithCompatible(true))
+```
+
+2. **Ensure struct definitions match**:
+
+```go
+// Both serializer and deserializer must have same struct
+type User struct {
+ ID int64
+ Name string
+}
+```
+
+3. **Regenerate codegen** (if using):
+
+```bash
+go generate ./...
+```
+
+### ErrKindMaxDepthExceeded
+
+**Error**: `max depth exceeded`
+
+**Cause**: Data nesting exceeds maximum depth limit.
+
+**Possible causes**:
+
+- Deeply nested data structures exceeding the default limit (20)
+- Unintended circular references without reference tracking enabled
+- **Malicious data**: Attackers may craft deeply nested payloads to cause
resource exhaustion
+
+**Solutions**:
+
+1. **Increase max depth** (default is 20):
+
+```go
+f := fory.New(fory.WithMaxDepth(50))
+```
+
+2. **Enable reference tracking** (for circular data):
+
+```go
+f := fory.New(fory.WithTrackRef(true))
+```
+
+3. **Check for unintended circular references** in your data.
+
+4. **Validate untrusted data**: When deserializing data from untrusted
sources, do not blindly increase max depth. Consider validating input size and
structure before deserialization.
+
+### ErrKindBufferOutOfBound
+
+**Error**: `buffer out of bound: offset=X, need=Y, size=Z`
+
+**Cause**: Reading beyond available data.
+
+**Solutions**:
+
+1. **Ensure complete data transfer**:
+
+```go
+// Wrong: Truncated data
+data := fullData[:100]
+f.Deserialize(data, &target) // Error if data was larger
+
+// Correct: Use full data
+f.Deserialize(fullData, &target)
+```
+
+2. **Check for data corruption**: Verify data integrity during transmission.
+
+### ErrKindInvalidRefId
+
+**Error**: `invalid reference ID`
+
+**Cause**: Reference to non-existent object in serialized data.
+
+**Solutions**:
+
+1. **Ensure reference tracking consistency**:
+
+```go
+// Serializer and deserializer must have same setting
+f1 := fory.New(fory.WithTrackRef(true))
+f2 := fory.New(fory.WithTrackRef(true)) // Must match!
+```
+
+2. **Check for data corruption**.
+
+### ErrKindInvalidTag
+
+**Error**: `invalid fory struct tag`
+
+**Cause**: Invalid struct tag configuration.
+
+**Common causes**:
+
+1. **Invalid tag ID**: ID must be >= -1
+
+```go
+// Wrong: negative ID (other than -1)
+type Bad struct {
+ Field int `fory:"id=-5"`
+}
+
+// Correct
+type Good struct {
+ Field int `fory:"id=0"`
+}
+```
+
+2. **Duplicate tag IDs**: Each field must have a unique ID within the struct
+
+```go
+// Wrong: duplicate IDs
+type Bad struct {
+ Field1 int `fory:"id=0"`
+ Field2 int `fory:"id=0"` // Duplicate!
+}
+
+// Correct
+type Good struct {
+ Field1 int `fory:"id=0"`
+ Field2 int `fory:"id=1"`
+}
+```
+
+## Cross-Language Issues
+
+### Field Order Mismatch
+
+**Symptom**: Data deserializes but fields have wrong values.
+
+**Cause**: Different field ordering between languages. In non-compatible mode,
fields are sorted by their snake_case names. CamelCase field names (e.g.,
`FirstName`) are converted to snake_case (e.g., `first_name`) for sorting.
+
+**Solutions**:
+
+1. **Ensure converted snake_case names are consistent**: Field names across
languages must produce the same snake_case ordering:
+
+```go
+type User struct {
+ FirstName string // Go: FirstName -> first_name
+ LastName string // Go: LastName -> last_name
+ // Sorted alphabetically by snake_case: first_name, last_name
+}
+```
+
+2. **Use field IDs for consistent ordering**: Field IDs (non-negative
integers) act as aliases for field names, used for both sorting and field
matching during deserialization:
+
+```go
+type User struct {
+ FirstName string `fory:"id=0"`
+ LastName string `fory:"id=1"`
+}
+```
+
+Ensure the same field IDs are used across all languages for corresponding
fields.
+
+### Name Registration Mismatch
+
+**Symptom**: `unknown type` in other languages.
+
+**Solution**: Use identical names:
+
+```go
+// Go
+f.RegisterNamedStruct(User{}, "example.User")
+
+// Java - must match exactly
+fory.register(User.class, "example.User");
+
+// Python
+fory.register(User, typename="example.User")
+```
+
+## Performance Issues
+
+### Slow Serialization
+
+**Possible causes**:
+
+1. **Large object graphs**: Reduce data size or serialize incrementally.
+
+2. **Excessive reference tracking**: Disable if not needed:
+
+```go
+f := fory.New(fory.WithTrackRef(false))
+```
+
+3. **Deep nesting**: Flatten data structures where possible.
+
+### High Memory Usage
+
+**Possible causes**:
+
+1. **Large serialized data**: Process in chunks.
+
+2. **Reference tracking overhead**: Disable if not needed.
+
+3. **Buffer not released**: Reuse buffers:
+
+```go
+buf := fory.NewByteBuffer(nil)
+f.SerializeTo(buf, value)
+// Process data
+buf.Reset() // Reuse for next serialization
+```
+
+### Thread Contention
+
+**Symptom**: Slowdown under concurrent load.
+
+**Solutions**:
+
+1. **Use per-goroutine instances** for hot paths:
+
+```go
+func worker() {
+ f := fory.New() // Each worker has own instance
+ for task := range tasks {
+ f.Serialize(task)
+ }
+}
+```
+
+2. **Profile pool usage** with thread-safe wrapper.
+
+## Debugging Techniques
+
+### Enable Debug Output
+
+Set environment variable:
+
+```bash
+ENABLE_FORY_DEBUG_OUTPUT=1 go test ./...
+```
+
+### Inspect Serialized Data
+
+```go
+data, _ := f.Serialize(value)
+fmt.Printf("Serialized %d bytes\n", len(data))
+fmt.Printf("Header: %x\n", data[:4]) // Magic + flags
+```
+
+### Check Type Registration
+
+```go
+// Verify type is registered
+f := fory.New()
+err := f.RegisterStruct(User{}, 1)
+if err != nil {
+ fmt.Printf("Registration failed: %v\n", err)
+}
+```
+
+### Compare Struct Hashes
+
+If getting hash mismatch, compare struct definitions:
+
+```go
+// Print struct info for debugging
+t := reflect.TypeOf(User{})
+for i := 0; i < t.NumField(); i++ {
+ f := t.Field(i)
+ fmt.Printf("Field: %s, Type: %s\n", f.Name, f.Type)
+}
+```
+
+## Testing Tips
+
+### Test Round-Trip
+
+```go
+func TestRoundTrip(t *testing.T) {
+ f := fory.New()
+ f.RegisterStruct(User{}, 1)
+
+ original := &User{ID: 1, Name: "Alice"}
+
+ data, err := f.Serialize(original)
+ require.NoError(t, err)
+
+ var result User
+ err = f.Deserialize(data, &result)
+ require.NoError(t, err)
+
+ assert.Equal(t, original.ID, result.ID)
+ assert.Equal(t, original.Name, result.Name)
+}
+```
+
+### Test Cross-Language
+
+```bash
+cd java/fory-core
+FORY_GO_JAVA_CI=1 mvn test -Dtest=org.apache.fory.xlang.GoXlangTest
+```
+
+### Test Schema Evolution
+
+```go
+func TestSchemaEvolution(t *testing.T) {
+ f1 := fory.New(fory.WithCompatible(true))
+ f1.RegisterStruct(UserV1{}, 1)
+
+ data, _ := f1.Serialize(&UserV1{ID: 1, Name: "Alice"})
+
+ f2 := fory.New(fory.WithCompatible(true))
+ f2.RegisterStruct(UserV2{}, 1)
+
+ var result UserV2
+ err := f2.Deserialize(data, &result)
+ require.NoError(t, err)
+}
+```
+
+## Getting Help
+
+If you encounter issues not covered here:
+
+1. **Check GitHub Issues**:
[github.com/apache/fory/issues](https://github.com/apache/fory/issues)
+2. **Enable debug output**: `ENABLE_FORY_DEBUG_OUTPUT=1`
+3. **Create minimal reproduction**: Isolate the problem
+4. **Report the issue**: Include Go version, Fory version, and minimal code
+
+## Related Topics
+
+- [Configuration](configuration)
+- [Cross-Language Serialization](cross-language)
+- [Schema Evolution](schema-evolution)
+- [Thread Safety](thread-safety)
diff --git a/docs/docs/guide/go/type-registration.md
b/docs/docs/guide/go/type-registration.md
new file mode 100644
index 000000000..87090d604
--- /dev/null
+++ b/docs/docs/guide/go/type-registration.md
@@ -0,0 +1,262 @@
+---
+title: Type Registration
+sidebar_position: 30
+id: go_type_registration
+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
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+---
+
+Type registration tells Fory how to identify and serialize your custom types.
Registration is required for struct, enum, and extension types.
+
+## Why Register Types?
+
+1. **Type Identification**: Fory needs to identify the actual type during
deserialization
+2. **Polymorphism**: When deserializing interface types, Fory must know which
concrete type to create
+3. **Cross-Language Compatibility**: Other languages need to recognize and
deserialize your types
+
+## Struct Registration
+
+### Register by ID
+
+Register a struct with a numeric type ID for compact serialization:
+
+```go
+type User struct {
+ ID int64
+ Name string
+}
+
+f := fory.New()
+err := f.RegisterStruct(User{}, 1)
+if err != nil {
+ panic(err)
+}
+```
+
+**ID Guidelines**:
+
+- IDs must be unique within your application
+- IDs must be consistent across all languages for cross-language serialization
+- Use the same ID for the same type in serializer and deserializer
+
+### Register by Name
+
+Register a struct with a type name string. This is more flexible but has
higher serialization cost:
+
+```go
+f := fory.New()
+err := f.RegisterNamedStruct(User{}, "example.User")
+if err != nil {
+ panic(err)
+}
+```
+
+**Name Guidelines**:
+
+- Use fully-qualified names following `namespace.TypeName` convention
+- Names must be unique and consistent across all languages
+- Names are case-sensitive
+
+## Enum Registration
+
+Go doesn't have native enums, but you can register integer types as enums:
+
+### Register by ID
+
+```go
+type Status int32
+
+const (
+ StatusPending Status = 0
+ StatusActive Status = 1
+ StatusComplete Status = 2
+)
+
+f := fory.New()
+err := f.RegisterEnum(Status(0), 1)
+```
+
+### Register by Name
+
+```go
+err := f.RegisterNamedEnum(Status(0), "example.Status")
+```
+
+## Extension Types
+
+For types requiring custom serialization logic, register as extension types
with a custom serializer:
+
+```go
+f := fory.New()
+
+// Register by ID
+err := f.RegisterExtension(CustomType{}, 1, &CustomSerializer{})
+
+// Or register by name
+err = f.RegisterNamedExtension(CustomType{}, "example.Custom",
&CustomSerializer{})
+```
+
+See [Custom Serializers](custom-serializers) for details on implementing the
`ExtensionSerializer` interface.
+
+## Registration Scope
+
+Type registration is per-Fory-instance:
+
+```go
+f1 := fory.New()
+f2 := fory.New()
+
+// Types registered on f1 are NOT available on f2
+f1.RegisterStruct(User{}, 1)
+
+// f2 cannot deserialize User unless also registered
+f2.RegisterStruct(User{}, 1)
+```
+
+## Registration Timing
+
+Register types after creating a Fory instance and before any
serialize/deserialize calls:
+
+```go
+f := fory.New()
+
+// Register before use
+f.RegisterStruct(User{}, 1)
+f.RegisterStruct(Order{}, 2)
+
+// Now serialize/deserialize
+data, _ := f.Serialize(&User{ID: 1, Name: "Alice"})
+```
+
+## Nested Type Registration
+
+Register all struct types in the object graph, including nested types:
+
+```go
+type Address struct {
+ City string
+ Country string
+}
+
+type Person struct {
+ Name string
+ Address Address
+}
+
+f := fory.New()
+
+// Register ALL struct types used in the object graph
+f.RegisterStruct(Address{}, 1)
+f.RegisterStruct(Person{}, 2)
+```
+
+## Cross-Language Registration
+
+For cross-language serialization, types must be registered consistently across
all languages.
+
+### Using IDs
+
+All languages use the same numeric ID:
+
+**Go**:
+
+```go
+f.RegisterStruct(User{}, 1)
+```
+
+**Java**:
+
+```java
+fory.register(User.class, 1);
+```
+
+**Python**:
+
+```python
+fory.register(User, type_id=1)
+```
+
+### Using Names
+
+All languages use the same type name:
+
+**Go**:
+
+```go
+f.RegisterNamedStruct(User{}, "example.User")
+```
+
+**Java**:
+
+```java
+fory.register(User.class, "example.User");
+```
+
+**Python**:
+
+```python
+fory.register(User, typename="example.User")
+```
+
+**Rust**:
+
+```rust
+#[derive(Fory)]
+struct User {
+ id: i64,
+ name: String,
+}
+
+let mut fory = Fory::default();
+fory.register_by_name::<User>("example.User")?;
+```
+
+## Best Practices
+
+1. **Register early**: Register all types at application startup before any
serialization
+2. **Be consistent**: Use the same ID or name across all languages and all
instances
+3. **Register all types**: Include nested struct types, not just top-level
types
+4. **Prefer IDs for performance**: Numeric IDs have lower serialization
overhead than names
+5. **Use names for flexibility**: Names are easier to manage and less prone to
conflicts
+
+## Common Errors
+
+### Unregistered Type
+
+```
+error: unknown type encountered
+```
+
+**Solution**: Register the type before serialization/deserialization.
+
+### ID/Name Mismatch
+
+Data serialized with one ID or name cannot be deserialized if registered with
a different ID or name.
+
+**Solution**: Use consistent IDs or names across serializer and deserializer.
+
+### Duplicate Registration
+
+Two types registered with the same ID will conflict.
+
+**Solution**: Ensure unique IDs for each type.
+
+## Related Topics
+
+- [Basic Serialization](basic-serialization)
+- [Cross-Language Serialization](cross-language)
+- [Supported Types](supported-types)
+- [Troubleshooting](troubleshooting)
diff --git a/docs/docs/guide/xlang/field-reference-tracking.md
b/docs/docs/guide/xlang/field-reference-tracking.md
index e003c59f5..4e67ac5b2 100644
--- a/docs/docs/guide/xlang/field-reference-tracking.md
+++ b/docs/docs/guide/xlang/field-reference-tracking.md
@@ -113,13 +113,13 @@ By default, **most fields do not track references** even
when global `refTrackin
### Default Behavior by Language
-| Language | Default Ref Tracking | Types That Track Refs by Default |
-| -------- | -------------------- | -------------------------------- |
-| Java | No | None (use annotation to enable) |
-| Python | No | None (use annotation to enable) |
-| Go | No | Pointer types (`*T`) |
-| C++ | No | `std::shared_ptr<T>` |
-| Rust | No | `Rc<T>`, `Arc<T>`, `Weak<T>` |
+| Language | Default Ref Tracking | Types That Track Refs by Default |
+| -------- | -------------------- | --------------------------------- |
+| Java | No | None (use annotation to enable) |
+| Python | No | None (use annotation to enable) |
+| Go | No | None (use `fory:"ref"` to enable) |
+| C++ | No | `std::shared_ptr<T>` |
+| Rust | No | `Rc<T>`, `Arc<T>`, `Weak<T>` |
### Customizing Per-Field Ref Tracking
@@ -181,11 +181,11 @@ struct Document {
type Document struct {
Title string
- // Pointer types track refs by default
- Author *Author
+ // Enable ref tracking for pointer to struct
+ Author *Author `fory:"ref"`
- // Use struct tag to control ref tracking
- Tags []Tag `fory:"trackRef"`
+ // Enable ref tracking for slice
+ Tags []Tag `fory:"ref"`
}
```
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]