Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

History

2,217 Commits
Apache Fory logo

Build StatusSlack ChannelXMaven VersionCrates.ioPyPInpmNuGetpub.dev

Apache Fory™ is a blazingly fast multi-language serialization framework for idiomatic domain objects, schema IDL, and cross-language data exchange.

https://fory.apache.org

Why Fory

Fory is built for fast, compact serialization across languages and implementations. It works with idiomatic objects in each language, supports shared schemas when you need a contract, and preserves object features such as shared and circular references.

  • Efficient Cross-Language Encoding: Exchange payloads across supported languages with compact binary encoding, metadata packing, schema evolution, shared/circular references, and polymorphic runtime types.
  • Domain Objects First: Serialize Java classes, Python dataclasses, Go structs, Rust/C++ structs, and generated or annotated model types directly. Preserve shared and circular references when object identity matters.
  • Reference-Aware Schema IDL: Support shared and circular references directly in the schema, alongside numbers, strings, lists, maps, arrays, enums, structs, and unions. Define schemas once, then generate native domain objects for each language without forcing wrapper types into user code.
  • Optimized Implementations: Java JIT serializers and generated/static serializers in other language implementations keep hot paths fast and payloads compact.
  • Language And Platform Support: Java, Python, C++, Go, Rust, JavaScript/TypeScript, C#, Swift, Dart, Scala, and Kotlin, including GraalVM native image, Android, Dart VM/Flutter/web, and Node.js/browser JavaScript.

For same-language workloads, Fory provides native serialization modes that support broader language-specific object models:

  • Java Native Serialization: A high-performance replacement for JDK serialization, Hessian, Kryo, and FST in Java-only systems. It supports JDK custom serialization semantics.
  • Python Native Serialization: A faster and more compact replacement for pickle and cloudpickle in Python-only systems. It supports classes, modules, functions, and custom object state, with fine-grained deserialization controls through DeserializationPolicy.

Fory also provides specialized formats for other data-processing requirements:

  • Row Format: Read fields, arrays, and nested values without rebuilding complete objects, with zero-copy access and partial reads.
  • Fory JSON: A Java JSON serialization framework built for maximum throughput through runtime-generated codecs and optimized readers and writers. Supports Java 8 and later on standard JDKs, GraalVM native images, and Android, including Java 17 records.

Performance

Benchmarks show Fory delivering higher throughput and smaller serialized payloads than common serialization frameworks on representative workloads. Java has the broadest comparison set; the other charts show language-specific results across supported languages.

JavaBenchmarks

In Java serialization benchmarks, Fory reaches up to 170x the throughput of JDK serialization on selected workloads.

Java serialization throughput

Java deserialization throughput

Java xlang throughput

PythonBenchmarks

Python serialization throughput

RustBenchmarks

Rust serialization throughput

Benchmarks for C++, Go, JavaScript/TypeScript, C#, Swift, and Dart

C++Benchmarks

C++ serialization throughput

GoBenchmarks

Go serialization throughput

JavaScript/TypeScriptBenchmarks

JavaScript serialization throughput

C#Benchmarks

C# serialization throughput

SwiftBenchmarks

Swift serialization throughput

DartBenchmarks

Dart serialization throughput

Installation

Pick your language and run the package-manager command, or paste the dependency block into your build file.

Java

Maven:

<dependency>
<groupId>org.apache.fory</groupId>
<artifactId>fory-core</artifactId>
<version>1.5.0</version>
</dependency>

Gradle:

implementation "org.apache.fory:fory-core:1.5.0"

On JDK25+, opening java.lang.invoke to Fory core is also recommended. It avoids the current-JDK Unsafe fallback and is required when Unsafe access is disabled or unavailable, including with --sun-misc-unsafe-memory-access=deny. Use ALL-UNNAMED when Fory is on the classpath:

--add-opens=java.base/java.lang.invoke=ALL-UNNAMED

Use the Fory core module name when Fory is on the module path:

--add-opens=java.base/java.lang.invoke=org.apache.fory.core

Scala

sbt:

libraryDependencies +="org.apache.fory"%%"fory-scala"%"1.5.0"

Kotlin

Gradle:

implementation("org.apache.fory:fory-kotlin:1.5.0")

Maven:

<dependency>
<groupId>org.apache.fory</groupId>
<artifactId>fory-kotlin</artifactId>
<version>1.5.0</version>
</dependency>

Python

pip install pyfory

For row-format support:

pip install "pyfory[format]"

Rust

Cargo.toml:

[dependencies]
fory = "1.5.0"

C++

CMake:

include(FetchContent)
FetchContent_Declare(
fory
GIT_REPOSITORY https://github.com/apache/fory.git
GIT_TAG v1.5.0
SOURCE_SUBDIR cpp
)
FetchContent_MakeAvailable(fory)
target_link_libraries(my_appPRIVATEfory::serialization)

Bazel:

# MODULE.bazelbazel_dep(name="fory", version="1.5.0")
git_override(module_name="fory", remote="https://github.com/apache/fory.git", commit="v1.5.0")
# BUILDdeps= ["@fory//cpp/fory/serialization:fory_serialization"]

When building C++ with MSVC, enable the conforming preprocessor option /Zc:preprocessor; see the C++ installation guide for setup details.

See the C++ installation guide for complete CMake, Bazel, and source-build details.

Go

go get github.com/apache/fory/go/fory

JavaScript/TypeScript

npm install @apache-fory/core

For the Node.js string fast path:

npm install @apache-fory/core @apache-fory/hps

C#

dotnet add package Apache.Fory --version 1.5.0

Dart

dart pub add fory:^1.5.0
dart pub add dev:build_runner

Swift

Add Fory to Package.swift:

dependencies:[.package(url:"https://github.com/apache/fory.git", exact:"1.5.0")],targets:[.target(
name:"YourTarget",
dependencies:[.product(name:"Fory",package:"fory")])]

See the Swift guide for generated serializer setup.

Development From Source

See docs/development/index.md.

Snapshots for Java, Scala, and Kotlin are available from https://repository.apache.org/snapshots/ with the matching -SNAPSHOT version.

Choose a Serialization Format

FormatUse it whenStart here
Xlang binary (default)Data crosses language boundariesCross-language interoperability
Native binaryProducer and consumer are in the same runtime familyNative guide
Row formatYou need random field access or analytics-style partial readsRow Format
Fory JSONJava applications need high-performance standard JSONFory JSON

For Java, Scala, Kotlin, Python, C++, Go, and Rust, use native mode for same-language traffic. It avoids xlang's cross-language type mapping and metadata constraints, stays closer to each language's native type system, and supports broader language-specific object graphs. Use it when both producer and consumer are in the same language family and you want the native object model rather than a portable cross-language schema.

For Java/JVM-only systems, native mode is the replacement path for JDK serialization, Kryo, FST, Hessian, and Java-only Protocol Buffers payloads. For Python-only systems, native mode is the replacement path for pickle and cloudpickle.

Compatible mode is Fory's schema-evolution mode. It writes the metadata readers and writers need to tolerate schema differences. It is the default for xlang mode and native mode in implementations that expose the option.

Use compatible mode when services deploy independently or when fields may be added or deleted over time. Set compatible mode to false only when every reader and writer always uses the same schema and you want faster serialization and smaller size. For xlang payloads, set compatible mode to false only after verifying that every language uses the same schema, or when native types are generated from Fory schema IDL.

For xlang, all peers must agree on type identity. Name-based registration is easier to read in examples. Numeric IDs are smaller and faster, but they require coordination across every reader and writer.

Cross-Language Serialization

Xlang mode writes the cross-language Fory wire format. Bytes produced by one language implementation can be read by another when every peer uses the same type identity, compatible mode setting, and field schema.

Java

importorg.apache.fory.Fory;
publicclassExample {
publicstaticclassPerson {
publicStringname;
publicintage;
}
publicstaticvoidmain(String[] args) {
Foryfory = Fory.builder().withXlang(true).build();
fory.register(Person.class, "example.Person");
Personperson = newPerson();
person.name = "Alice";
person.age = 30;
byte[] bytes = fory.serialize(person);
Persondecoded = (Person) fory.deserialize(bytes);
System.out.println(decoded.name);
}
}

Python

fromdataclassesimportdataclassimportpyfory@dataclassclassPerson:
name: strage: pyfory.Int32fory=pyfory.Fory(xlang=True)
fory.register_type(Person, name="example.Person")
data=fory.serialize(Person("Alice", 30))
person=fory.deserialize(data)
print(person.name)

Go

package main
import (
"fmt""github.com/apache/fory/go/fory"
)
typePersonstruct {
NamestringAgeint32
}
funcmain() {
f:=fory.New(fory.WithXlang(true))
iferr:=f.RegisterStructByName(Person{}, "example.Person"); err!=nil {
panic(err)
}
data, _:=f.Serialize(&Person{Name: "Alice", Age: 30})
varpersonPersoniferr:=f.Deserialize(data, &person); err!=nil {
panic(err)
}
fmt.Println(person.Name)
}

Rust

use fory::{Error,Fory,ForyStruct};#[derive(ForyStruct,Debug,PartialEq)]structPerson{name:String,age:i32,}fnmain() -> Result<(),Error>{letmut fory = Fory::builder().xlang(true).build();
fory.register_by_name::<Person>("example.Person")?;let bytes = fory.serialize(&Person{name:"Alice".to_string(),age:30,})?;let person:Person = fory.deserialize(&bytes)?;println!("{}", person.name);Ok(())}

C++

#include"fory/serialization/fory.h"
#include<cstdint>
#include<iostream>
#include<string>usingnamespacefory::serialization;structPerson {
std::string name;
int32_t age;
};
FORY_STRUCT(Person, name, age);
intmain() {
auto fory = Fory::builder().xlang(true).build();
fory.register_struct<Person>("example.Person");
auto bytes = fory.serialize(Person{"Alice", 30}).value();
Person person = fory.deserialize<Person>(bytes).value();
std::cout << person.name << std::endl;
}

JavaScript/TypeScript

importFory,{Type}from"@apache-fory/core";constpersonType=Type.struct({typeName: "example.Person"},{name: Type.string(),age: Type.int32(),},);constfory=newFory();const{ serialize, deserialize }=fory.register(personType);constbytes=serialize({name: "Alice",age: 30});constperson=deserialize(bytes);console.log(person.name);

C#

usingApache.Fory;[ForyStruct]publicsealedclassPerson{publicstringName{get;set;}=string.Empty;publicintAge{get;set;}}Foryfory=Fory.Builder().Build();fory.Register<Person>("example","Person");byte[]bytes=fory.Serialize(newPerson{Name="Alice",Age=30});Personperson=fory.Deserialize<Person>(bytes);Console.WriteLine(person.Name);

C# always writes the xlang frame header, so there is no separate xlang builder flag.

Dart

import'package:fory/fory.dart';
part'person.fory.dart';
@ForyStruct()
classPerson {
Person();
String name ='';
@ForyField(type:Int32Type())
int age =0;
}
voidmain() {
final fory =Fory();
PersonFory.register(
fory,
Person,
name:'example.Person',
);
final bytes = fory.serialize(Person()
..name ='Alice'
..age =30);
final person = fory.deserialize<Person>(bytes);
print(person.name);
}

Dart uses the xlang wire format directly. Generate the companion file before running:

dart run build_runner build

Swift

import Fory
@ForyStructstructPerson{varname:String=""varage:Int32=0}letfory=Fory()try fory.register(Person.self, name:"example.Person")letbytes=try fory.serialize(Person(name:"Alice", age:30))letperson:Person=try fory.deserialize(bytes)print(person.name)

Scala

importorg.apache.fory.scala.ForyScalacaseclassPerson(name: String, age: Int)
valfory=ForyScala.builder().withXlang(true).build()
fory.register(classOf[Person], "example.Person")
valbytes= fory.serialize(Person("Alice", 30))
valperson= fory.deserialize(bytes).asInstanceOf[Person]
println(person.name)

Kotlin

importorg.apache.fory.kotlin.ForyKotlindata classPerson(valname:String, valage:Int)
funmain() {
val fory =ForyKotlin.builder().withXlang(true).build()
fory.register(Person::class.java, "example.Person")
val bytes = fory.serialize(Person("Alice", 30))
val person = fory.deserialize(bytes) asPersonprintln(person.name)
}

For shared/circular references, polymorphism, numeric IDs versus names, and type-mapping rules, see the cross-language guide and type mapping specification.

Native Serialization

Use native mode when the writer and reader are in the same language. It is optimized for each language's native type system and can cover language-specific types, object graphs, and framework-replacement cases that xlang mode keeps out of the portable wire format. The languages below expose an explicit xlang=false or native-mode setting; implementations without that switch stay on their documented default path.

Choose Java native mode for Java/JVM-only replacements of JDK serialization, Kryo, FST, Hessian, or Java-only Protocol Buffers payloads. Choose Python native mode when replacing pickle or cloudpickle for Python-only payloads.

Keep class/type registration enabled for untrusted input. See the language guides for language-specific security and compatibility settings.

Java

Foryfory = Fory.builder()
.withXlang(false)
.requireClassRegistration(true)
.build();
// Register, serialize, and deserialize as in the xlang example above.

Python

fory=pyfory.Fory(xlang=False, ref=True)
# Register, serialize, and deserialize as in the xlang example above.

Go

f:=fory.New(fory.WithXlang(false))
// Register, serialize, and deserialize as in the xlang example above.

Rust

letmut fory = Fory::builder().xlang(false).build();// Register, serialize, and deserialize as in the xlang example above.

C++

auto fory = Fory::builder().xlang(false).build();
// Register, serialize, and deserialize as in the xlang example above.

Scala

importorg.apache.fory.scala.ForyScalavalfory=ForyScala.builder()
.withXlang(false)
.requireClassRegistration(true)
.build()
// Register, serialize, and deserialize as in the xlang example above.

Kotlin

importorg.apache.fory.kotlin.ForyKotlinval fory =ForyKotlin.builder()
.withXlang(false)
.requireClassRegistration(true)
.build()
// Register, serialize, and deserialize as in the xlang example above.

Schema IDL

Fory IDL is Fory's schema-first path for shared data models. Use it when multiple languages need one explicit contract, stable field identities, and generated native domain objects instead of manually coordinating equivalent types in every implementation.

The schema supports primitive values, nullable fields, lists, maps, dense arrays, enums, messages, unions, imports, and first-class shared or circular references. The compiler generates idiomatic models and Fory integration for Java, Python, C++, Go, Rust, JavaScript/TypeScript, C#, Swift, Dart, Scala, and Kotlin. It can also generate Fory-backed gRPC service companions for supported languages.

Install the compiler from PyPI:

pip install fory-compiler

Define the shared model in tree.fdl:

packagetree;
messageTreeNode {
stringid=1;
stringname=2;
list<ref TreeNode> children = 3;
ref(weak=true) TreeNodeparent=4; // back-pointer
}

Generate native models for the languages used by your application:

foryc tree.fdl --lang java,python,rust --output ./generated

Generated types use each language's normal classes, structs, dataclasses, annotations, macros, or registration helpers, so application code works with native domain objects while all peers share the same Fory schema. See the Fory IDL and compiler guide for the complete type system, language-specific output options, schema evolution, and gRPC generation.

Row Format

Row format is for random access and partial reads. These examples encode an object with an integer array field, then read one array element from the binary row without rebuilding the object.

Python

fromdataclassesimportdataclassfromtypingimportListimportpyfory@dataclassclassUser:
id: pyfory.Int32name: strscores: List[pyfory.Int32]
encoder=pyfory.encoder(User)
binary=encoder.to_row(User(1, "Alice", [98, 100, 95])).to_bytes()
row=pyfory.RowData(encoder.schema, binary)
print(row.name)
print(row.scores[1])

Java

publicclassUser {
publicintid;
publicStringname;
publicint[] scores;
}
RowEncoder<User> encoder = Encoders.bean(User.class);
Useruser = newUser();
user.id = 1;
user.name = "Alice";
user.scores = newint[] {98, 100, 95};
BinaryRowrow = encoder.toRow(user);
Schemaschema = encoder.schema();
Schema.StringFieldnameField = schema.stringField("name");
Schema.ArrayFieldscoresField = schema.arrayField("scores");
Stringname = nameField.get(row);
ArrayDatascores = scoresField.get(row);
intsecondScore = scores.getInt32(1);

For Java imports, nested structs, arrays/maps, Arrow integration, and partial deserialization, see the Java row-format guide, Python row-format guide, C++ row-format guide, Rust row-format guide, and row-format specification.

Fory JSON

Fory JSON is a thread-safe JSON serialization framework for Java, extensively optimized for maximum performance across JSON encoding, decoding, and Java object mapping. It supports Java 8 and later on standard JDKs, GraalVM native images, and Android, with Java records supported on Java 17 and later.

Performance

The benchmark compares fory-json with Jackson and Gson using String and UTF-8 byte APIs. The String group excludes UTF-8 conversion. Gson's byte results include its required String/UTF-8 conversion. Higher throughput is better. See the full benchmark report for more details.

Java JSON String throughputJava JSON UTF-8 bytes throughput

RepresentationOperationfory-json ops/secJackson ops/secGson ops/sec
StringSerialize7,387,4652,049,3681,084,042
StringDeserialize2,897,9551,074,885902,772
UTF-8 bytesSerialize10,375,4981,868,6141,037,211
UTF-8 bytesDeserialize3,077,1581,268,397933,079

Add Fory JSON to your project:

Maven

<dependency>
<groupId>org.apache.fory</groupId>
<artifactId>fory-json</artifactId>
<version>1.5.0</version>
</dependency>

Gradle

implementation "org.apache.fory:fory-json:1.5.0"

Keep all Fory modules in the same application on the same version.

Quick Start

Build one ForyJson instance and reuse it across threads:

importorg.apache.fory.json.ForyJson;
publicfinalclassJsonExample {
privatestaticfinalForyJsonJSON = ForyJson.builder().build();
publicstaticfinalclassUser {
publiclongid;
publicStringname;
publicUser() {}
publicUser(longid, Stringname) {
this.id = id;
this.name = name;
}
}
publicstaticvoidmain(String[] args) {
Userinput = newUser(7, "Alice");
Stringtext = JSON.toJson(input);
UserfromText = JSON.fromJson(text, User.class);
byte[] bytes = JSON.toJsonBytes(input);
UserfromBytes = JSON.fromJson(bytes, User.class);
System.out.println(fromText.name + " / " + fromBytes.name);
}
}

Start with the Fory JSON module README, then use the Fory JSON documentation for the complete mapping, annotation, codec, security, and platform guides.

Documentation

User Guides

GuideSourceWebsite
Javadocs/object-serialization/javaView
Pythondocs/object-serialization/pythonView
Rustdocs/object-serialization/rustView
C++docs/object-serialization/cppView
Godocs/object-serialization/goView
JavaScript/TypeScriptdocs/object-serialization/javascriptView
C#docs/object-serialization/csharpView
Swiftdocs/object-serialization/swiftView
Dartdocs/object-serialization/dartView
Scaladocs/object-serialization/scalaView
Kotlindocs/object-serialization/kotlinView
Cross-language xlangdocs/object-serialization/xlang.mdView
Schema IDL/compilerdocs/compilerView
GraalVM native imagedocs/object-serialization/java/graalvm.mdView
Androiddocs/object-serialization/java/android.mdView
Developmentdocs/development/index.mdView

Specifications

SpecificationSourceWebsite
Xlang serializationxlang_serialization_spec.mdView
Java serializationjava_serialization_spec.mdView
Row formatrow_format_spec.mdView
Cross-language mappingxlang_type_mapping.mdView

Community

Contributing

Read CONTRIBUTING.md and docs/development/index.md before sending pull requests. Bug reports, docs fixes, tests, benchmarks, and implementation improvements are welcome.

License

Apache Fory™ is licensed under the Apache License 2.0.

About

A blazingly fast multi-language serialization framework for idiomatic domain objects, schema IDL, and cross-language data exchange.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

4.4k stars

Watchers

47 watching

Forks

Releases

Packages

Used by

Contributors

Languages