
Apache Fory™ is a blazingly fast multi-language serialization framework for idiomatic domain objects, schema IDL, and cross-language data exchange.
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.
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.
Java Benchmarks
In Java serialization benchmarks, Fory reaches up to 170x the throughput of JDK serialization on selected workloads.



Python Benchmarks

Rust Benchmarks

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

Go Benchmarks

JavaScript/TypeScript Benchmarks

C# Benchmarks

Swift Benchmarks

Dart Benchmarks

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.2.0</version>
</dependency>
Gradle:
implementation "org.apache.fory:fory-core:1.2.0"
On JDK25+, open java.lang.invoke to Fory. 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.2.0"
Kotlin
Gradle:
implementation("org.apache.fory:fory-kotlin:1.2.0")
Maven:
<dependency>
<groupId>org.apache.fory</groupId>
<artifactId>fory-kotlin</artifactId>
<version>1.2.0</version>
</dependency>
Python
pip install pyfory
For row-format support:
pip install "pyfory[format]"
Rust
Cargo.toml:
[dependencies]
fory = "1.2.0"
C++
CMake:
include(FetchContent)
FetchContent_Declare(
fory
GIT_REPOSITORY https://github.com/apache/fory.git
GIT_TAG v1.2.0
SOURCE_SUBDIR cpp
)
FetchContent_MakeAvailable(fory)
target_link_libraries(my_app PRIVATE fory::serialization)
Bazel:
# MODULE.bazel
bazel_dep(name = "fory", version = "1.2.0")
git_override(module_name = "fory", remote = "https://github.com/apache/fory.git", commit = "v1.2.0")
# BUILD
deps = ["@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.2.0
Dart
dart pub add fory:^1.2.0
dart pub add dev:build_runner
Swift
Add Fory to Package.swift:
dependencies: [
.package(url: "https://github.com/apache/fory.git", exact: "1.2.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.md.
Snapshots for Java, Scala, and Kotlin are available from
https://repository.apache.org/snapshots/ with the matching -SNAPSHOT version.
| Mode | Use it when | Start here |
|---|---|---|
| Xlang mode | Data crosses language boundaries | Cross-language guide |
| Native mode | Producer and consumer are in the same language | Language guide |
| Row format | You need random field access or analytics-style partial reads | Row format spec |
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.
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
import org.apache.fory.Fory;
public class Example {
public static class Person {
public String name;
public int age;
}
public static void main(String[] args) {
Fory fory = Fory.builder().withXlang(true).build();
fory.register(Person.class, "example.Person");
Person person = new Person();
person.name = "Alice";
person.age = 30;
byte[] bytes = fory.serialize(person);
Person decoded = (Person) fory.deserialize(bytes);
System.out.println(decoded.name);
}
}
Python
from dataclasses import dataclass
import pyfory
@dataclass
class Person:
name: str
age: pyfory.Int32
fory = 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"
)
type Person struct {
Name string
Age int32
}
func main() {
f := fory.New(fory.WithXlang(true))
if err := f.RegisterStructByName(Person{}, "example.Person"); err != nil {
panic(err)
}
data, _ := f.Serialize(&Person{Name: "Alice", Age: 30})
var person Person
if err := f.Deserialize(data, &person); err != nil {
panic(err)
}
fmt.Println(person.Name)
}
Rust
use fory::{Error, Fory, ForyStruct};
#[derive(ForyStruct, Debug, PartialEq)]
struct Person {
name: String,
age: i32,
}
fn main() -> Result<(), Error> {
let mut 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>
using namespace fory::serialization;
struct Person {
std::string name;
int32_t age;
};
FORY_STRUCT(Person, name, age);
int main() {
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
import Fory, { Type } from "@apache-fory/core";
const personType = Type.struct(
{ typeName: "example.Person" },
{
name: Type.string(),
age: Type.int32(),
},
);
const fory = new Fory();
const { serialize, deserialize } = fory.register(personType);
const bytes = serialize({ name: "Alice", age: 30 });
const person = deserialize(bytes);
console.log(person.name);
C#
```csharp using Apache.Fory;
[ForyStruct] public sealed class Person { public string Name { get; set; } = string.Em