Skip to main content
Version: dev

Schema Metadata

JavaScript schema metadata is declared with Type.* builders or TypeScript decorators. Metadata defines type identity, field types, nullability, reference tracking, dynamic fields, and per-struct schema evolution behavior.

Type Identity

Structs and enums can use a numeric ID or a namespace/name pair. Pick one identity strategy for a type and use it consistently in every runtime that reads or writes the payload.

import { Type } from "@apache-fory/core";

const byId = Type.struct(
{ typeId: 1001 },
{
id: Type.int64(),
name: Type.string(),
},
);

const byName = Type.struct(
{ namespace: "example", typeName: "user" },
{
id: Type.int64(),
name: Type.string(),
},
);

Decorator Metadata

Decorators keep the schema next to a TypeScript class declaration:

@Type.struct({ typeName: "example.user" })
class User {
@Type.int64()
id!: bigint;

@Type.string()
name!: string;
}

The decorator metadata is equivalent to the builder metadata registered with fory.register(...).

Field Types

Use explicit scalar builders for stable contracts:

Type.int8();
Type.int16();
Type.int32();
Type.int64(); // JavaScript value is bigint
Type.uint32();
Type.uint64(); // JavaScript value is bigint
Type.float16();
Type.bfloat16();
Type.float32();
Type.float64();
Type.string();
Type.binary();

Use collection builders for nested values:

Type.list(Type.string());
Type.map(Type.string(), Type.int32());
Type.set(Type.string());
Type.int32Array();
Type.float64Array();

Nullability

Fields are non-nullable unless the schema says otherwise:

const userType = Type.struct("example.user", {
name: Type.string(),
email: Type.string().setNullable(true),
});

Passing null to a non-nullable field throws.

Reference Tracking

When the same object instance can appear in multiple fields, or when an object graph can be circular, enable global reference tracking and mark reference-tracked fields:

import Fory, { Type } from "@apache-fory/core";

const fory = new Fory({ ref: true });

const nodeType = Type.struct("example.node", {
next: Type.struct("example.node").setNullable(true).setTrackingRef(true),
});

Field-level reference metadata has no effect unless new Fory({ ref: true }) is also set.

Dynamic Fields

Use Type.any() when a field can hold different Fory values at runtime:

const eventType = Type.struct("example.event", {
kind: Type.string(),
payload: Type.any(),
});

For a struct field with a declared type, .setDynamic(Dynamic.FALSE) always treats values as the declared type and .setDynamic(Dynamic.TRUE) always writes the runtime type. The default Dynamic.AUTO is appropriate for most fields.

Per-Struct Schema Evolution

JavaScript uses compatible schema evolution by default. For a stable struct that should omit evolution metadata, set evolving: false:

const fixedType = Type.struct(
{ typeId: 1002, evolving: false },
{
name: Type.string(),
},
);

Both writer and reader must agree on evolving: false.