Skip to main content
Version: dev

Protobuf IDL Support

This page explains how Apache Fory works with Protocol Buffers (.proto) schemas, how protobuf concepts map to Fory, and how to use protobuf-only Fory extension options.

What This Page Covers

  • Choosing protobuf vs Fory for your use case
  • Syntax and semantic differences that matter during migration
  • Supported Fory extension options in protobuf files
  • Practical migration patterns from protobuf to Fory

Quick Decision Guide

SituationRecommended Format
You are building gRPC APIs and rely on protobuf toolingProtocol Buffers
You need maximum object-graph performance and ref trackingFory
You need circular/shared references in serialized dataFory
You need strong unknown-field behavior for wire compatibilityProtocol Buffers
You need native structs/classes instead of protobuf wrappersFory

Protobuf vs Fory at a Glance

AspectProtocol BuffersFory
Primary purposeRPC/message contractsHigh-performance object serialization
Encoding modelTag-length-valueFory binary protocol
Reference trackingNot built-inFirst-class (ref)
Circular refsNot supportedSupported
Unknown fieldsPreservedNot preserved
Generated typesProtobuf-specific model typesNative language constructs
gRPC ecosystemNativeIn progress (active development)

Fory gRPC support is under active development. For production gRPC workflows today, protobuf remains the mature/default choice.

Why Use Apache Fory

  • Idiomatic generated code: Fory IDL generates language-idiomatic classes and structs that can be used directly as domain objects.
  • Faster serialization: In Fory benchmarks, Fory can be around 10x faster than protobuf for object serialization workloads.
  • Better graph modeling: Shared and circular references are first-class features instead of application-level ID-link workarounds.

See benchmark details under Performance References.

Syntax and Semantic Mapping

Package and File Options

Protocol Buffers

syntax = "proto3";
package example.models;
option java_package = "com.example.models";
option go_package = "example.com/models";

Fory

package example.models;

Fory uses one package namespace for cross-language registration. Language-specific package placement is still configurable in code generation.

Message and Enum Definitions

Protocol Buffers

message User {
string id = 1;
string name = 2;
optional string email = 3;
int32 age = 4;
repeated string tags = 5;
map<string, string> metadata = 6;
}

enum Status {
STATUS_UNSPECIFIED = 0;
STATUS_ACTIVE = 1;
}

Fory

message User [id=101] {
string id = 1;
string name = 2;
optional string email = 3;
int32 age = 4;
list<string> tags = 5;
map<string, string> metadata = 6;
}

enum Status [id=102] {
UNKNOWN = 0;
ACTIVE = 1;
}

Key differences:

  • Fory can assign stable type IDs directly ([id=...]).
  • Fory uses list<T> (with repeated T as alias).
  • Enum naming conventions are language-driven instead of protobuf prefix style.

oneof to union

Protobuf oneof is translated to a nested Fory union plus an optional field referencing that union.

Protocol Buffers

message Event {
oneof payload {
string text = 1;
int32 number = 2;
}
}

Fory-style shape after translation

message Event {
union payload {
string text = 1;
int32 number = 2;
}
optional payload payload = 1;
}

Notes:

  • Union case IDs are derived from the original oneof field numbers.
  • The synthetic union field uses the smallest oneof case number.

Imports and Well-Known Types

Protobuf imports are supported. Common well-known types map directly:

  • google.protobuf.Timestamp -> timestamp
  • google.protobuf.Duration -> duration
  • google.protobuf.Any -> any

Type Mapping Highlights

Protobuf TypeFory Mapping
boolbool
int32, uint32variable-length 32-bit integer kinds
sint32zigzag 32-bit integer
int64, uint64variable-length 64-bit integer kinds
sint64zigzag 64-bit integer
fixed32, fixed64fixed-width unsigned integer kinds
sfixed32, sfixed64fixed-width signed integer kinds
float, doublefloat32, float64
string, bytesstring, bytes
repeated Tlist<T>
map<K, V>map<K, V>
optional Toptional T
oneofunion + optional union reference field
int64 [(fory).type = "tagged_int64"]tagged_int64 encoding
uint64 [(fory).type = "tagged_uint64"]tagged_uint64 encoding

Fory Extension Options (Protobuf)

Fory-specific options in .proto use the (fory). prefix.

option (fory).enable_auto_type_id = true;

message TreeNode {
TreeNode parent = 1 [(fory).weak_ref = true];
repeated TreeNode children = 2 [(fory).ref = true];
}

File-Level Options

OptionTypeDescription
(fory).use_record_for_java_messageboolGenerate Java records for all messages in this file
(fory).polymorphismboolEnable polymorphic serialization metadata by default
(fory).enable_auto_type_idboolAuto-generate type IDs when omitted (compiler default is true)
(fory).evolvingboolDefault schema-evolution behavior for messages
(fory).go_nested_type_stylestringGo nested naming style: underscore (default) or camelcase

Message and Enum Options

OptionApplies ToTypeDescription
(fory).idmessage, enumintExplicit type ID for registration
(fory).aliasmessage, enumstringAlternate name used for auto-ID hashing
(fory).evolvingmessageboolOverride file-level evolution setting
(fory).use_record_for_javamessageboolGenerate Java record for this message
(fory).deprecatedmessage, enumboolMark type as deprecated
(fory).namespacemessagestringOverride default package-based namespace

Field-Level Options

OptionTypeDescription
(fory).refboolEnable reference tracking for this field
(fory).nullableboolTreat field as nullable (optional)
(fory).weak_refboolGenerate weak pointer semantics (C++/Rust codegen)
(fory).thread_safe_pointerboolRust pointer flavor for ref fields (Arc vs Rc)
(fory).deprecatedboolMark field as deprecated
(fory).typestringPrimitive override, currently tagged_int64/tagged_uint64

Reference option behavior:

  • weak_ref = true implies ref tracking.
  • For repeated fields, (fory).ref = true applies to list elements.
  • For map<K, V> fields, (fory).ref = true applies to map values.
  • weak_ref and thread_safe_pointer are codegen hints for C++/Rust.

Option Examples by Shape

message Graph {
Node root = 1 [(fory).ref = true, (fory).thread_safe_pointer = false];
repeated Node nodes = 2 [(fory).ref = true];
map<string, Node> cache = 3 [(fory).ref = true];
Node parent = 4 [(fory).weak_ref = true];
}

Reference Tracking vs Protobuf IDs

Protobuf itself does not preserve shared/cyclic object graphs. With Fory protobuf extensions, you can opt into graph semantics.

Without Fory ref options (protobuf-style IDs):

message TreeNode {
string id = 1;
string parent_id = 2;
repeated string child_ids = 3;
}

With Fory ref options (object graph):

message TreeNode {
TreeNode parent = 1 [(fory).weak_ref = true];
repeated TreeNode children = 2 [(fory).ref = true];
}

Migration Guide: Protobuf to Fory

Step 1: Translate Schema Syntax

  • Keep package names stable.
  • Replace repeated T with list<T> (or keep repeated alias).
  • Add explicit [id=...] where you need stable numeric registration.

Step 2: Convert oneof and Special Types

  • oneof -> union + optional union field.
  • Map protobuf well-known types to Fory primitives (timestamp, duration, any).

Step 3: Replace Protobuf Workarounds with ref

Where protobuf used manual ID links for object graphs, switch to Fory ref modifiers (and optional ref(weak=true) where needed).

Step 4: Update Build/Codegen

Replace protobuf generation steps with the Fory compiler invocation for target languages.

Step 5: Run Compatibility Checks

For staged migrations, keep both formats in parallel and verify payload-level parity with integration tests.

Coexistence Strategy

You can run protobuf and Fory in parallel during migration:

public byte[] serialize(Object obj, Format format) {
if (format == Format.PROTOBUF) {
return ((MessageLite) obj).toByteArray();
}
return fory.serialize(obj);
}

Use translators at service boundaries while internal object-graph heavy paths migrate first.

Performance References

Summary

Use protobuf when your primary concern is API contracts and gRPC ecosystem integration. Use Fory when object-graph performance, native models, and reference semantics are the primary concern.