Schema IDL
This document provides the syntax and semantic reference for Fory IDL.
For compiler usage and build integration, see Compiler Guide. For protobuf/FlatBuffers frontend mapping rules, see Protocol Buffers IDL Support and FlatBuffers IDL Support.
File Structure
An Fory IDL file typically consists of:
- Optional package declaration
- Optional file-level options
- Optional import statements
- Type definitions (enums, messages, and unions)
// Optional package declaration
package com.example.models;
// Optional file-level options
option java_package = "com.example.models";
// Import statements
import "common/types.fdl";
// Type definitions
enum Color [id=100] { ... }
message User [id=101] { ... }
message Order [id=102] { ... }
union Event [id=103] { ... }
Comments
Fory IDL supports both single-line and block comments:
// This is a single-line comment
/*
* This is a block comment
* that spans multiple lines
*/
message Example {
string name = 1; // Inline comment
}
Package Declaration
The package declaration defines the namespace for all types in the file.
package com.example.models;
You can optionally specify a package alias used for auto-generated type IDs:
package com.example.models alias models_v1;
Rules:
- Optional but recommended
- Must appear before any type definitions
- Only one package declaration per file
- Used for namespace-based type registration
- Package alias is used for auto-ID hashing
Language Mapping:
| Language | Package Usage |
|---|---|
| Java | Java package |
| Python | Module name (dots to underscores) |
| Go | Package name (last component) |
| Rust | Module name (dots to underscores) |
| C++ | Namespace (dots to ::) |
File-Level Options
Options can be specified at file level to control language-specific code generation.
Syntax
option option_name = value;
Java Package Option
Override the Java package for generated code:
package payment;
option java_package = "com.mycorp.payment.v1";
message Payment {
string id = 1;
}
Effect:
- Generated Java files will be in
com/mycorp/payment/v1/directory - Java package declaration will be
package com.mycorp.payment.v1; - Type registration still uses the Fory IDL package (
payment) for cross-language compatibility
Go Package Option
Specify the Go import path and package name:
package payment;
option go_package = "github.com/mycorp/apis/gen/payment/v1;paymentv1";
message Payment {
string id = 1;
}
Format: "import/path;package_name" or just "import/path" (last segment used as package name)
Effect:
- Generated Go files will have
package paymentv1 - The import path can be used in other Go code
- Type registration still uses the Fory IDL package (
payment) for cross-language compatibility
Java Outer Classname Option
Generate all types as inner classes of a single outer wrapper class:
package payment;
option java_outer_classname = "DescriptorProtos";
enum Status {
UNKNOWN = 0;
ACTIVE = 1;
}
message Payment {
string id = 1;
Status status = 2;
}
Effect:
- Generates a single file
DescriptorProtos.javainstead of separate files - All enums and messages become
public staticinner classes - The outer class is
public finalwith a private constructor - Useful for grouping related types together
Generated structure:
public final class DescriptorProtos {
private DescriptorProtos() {}
public static enum Status {
UNKNOWN,
ACTIVE;
}
public static class Payment {
private String id;
private Status status;
// ...
}
}
Combined with java_package:
package payment;
option java_package = "com.example.proto";
option java_outer_classname = "PaymentProtos";
message Payment {
string id = 1;
}
This generates com/example/proto/PaymentProtos.java with all types as inner classes.
Java Multiple Files Option
Control whether types are generated in separate files or as inner classes:
package payment;
option java_outer_classname = "PaymentProtos";
option java_multiple_files = true;
message Payment {
string id = 1;
}
message Receipt {
string id = 1;
}
Behavior:
java_outer_classname | java_multiple_files | Result |
|---|---|---|
| Not set | Any | Separate files (one per type) |
| Set | false (default) | Single file with all types as inner classes |
| Set | true | Separate files (overrides outer class) |
Effect of java_multiple_files = true:
- Each top-level enum and message gets its own
.javafile - Overrides
java_outer_classnamebehavior - Useful when you want separate files but still specify an outer class name for other purposes
Example without java_multiple_files (default):
option java_outer_classname = "PaymentProtos";
// Generates: PaymentProtos.java containing Payment and Receipt as inner classes
Example with java_multiple_files = true:
option java_outer_classname = "PaymentProtos";
option java_multiple_files = true;
// Generates: Payment.java, Receipt.java (separate files)
Multiple Options
Multiple options can be specified:
package payment;
option java_package = "com.mycorp.payment.v1";
option go_package = "github.com/mycorp/apis/gen/payment/v1;paymentv1";
option deprecated = true;
message Payment {
string id = 1;
}
Protobuf Compatibility Options
Fory IDL accepts protobuf-style extension syntax (for example, (fory).id) for
compatibility, but native Fory IDL style uses plain option keys such as id,
evolving, ref, and nullable without the (fory) prefix.
Equivalent forms:
// Native Fory IDL style (preferred in .fdl files)
message Node [id=100] {
ref Node parent = 1;
optional string nickname = 2;
}
// Protobuf-style compatibility syntax
message Node {
option (fory).id = 100;
Node parent = 1 [(fory).ref = true];
string nickname = 2 [(fory).nullable = true];
}
For the protobuf-specific extension option guide, see Protocol Buffers IDL Support.
Option Priority
For language-specific packages:
- Command-line package override (highest priority)
- Language-specific option (
java_package,go_package) - Fory IDL package declaration (fallback)
Example:
package myapp.models;
option java_package = "com.example.generated";
| Scenario | Java Package Used |
|---|---|
| No override | com.example.generated |
CLI: --package=override | override |
| No java_package option | myapp.models (fallback) |
Cross-Language Type Registration
Language-specific options only affect where code is generated, not the type namespace used for serialization. This ensures cross-language compatibility:
package myapp.models;
option java_package = "com.mycorp.generated";
option go_package = "github.com/mycorp/gen;genmodels";
message User {
string name = 1;
}
All languages will register User with namespace myapp.models, enabling:
- Java serialized data → Go deserialization
- Go serialized data → Java deserialization
- Any language combination works seamlessly
Import Statement
Import statements allow you to use types defined in other Fory IDL files.
Basic Syntax
import "path/to/file.fdl";
Multiple Imports
import "common/types.fdl";
import "common/enums.fdl";
import "models/address.fdl";
Path Resolution
Import paths are resolved relative to the importing file:
project/
├── common/
│ └── types.fdl
├── models/
│ ├── user.fdl # import "../common/types.fdl"
│ └── order.fdl # import "../common/types.fdl"
└── main.fdl # import "common/types.fdl"
Rules:
- Import paths are quoted strings (double or single quotes)
- Paths are resolved relative to the importing file's directory
- Imported types become available as if defined in the current file
- Circular imports are detected and reported as errors
- Transitive imports work (if A imports B and B imports C, A has access to C's types)
Complete Example
common/types.fdl:
package common;
enum Status [id=100] {
PENDING = 0;
ACTIVE = 1;
COMPLETED = 2;
}
message Address [id=101] {
string street = 1;
string city = 2;
string country = 3;
}
models/user.fdl:
package models;
import "../common/types.fdl";
message User [id=200] {
string id = 1;
string name = 2;
Address home_address = 3; // Uses imported type
Status status = 4; // Uses imported enum
}
Unsupported Import Syntax
The following protobuf import modifiers are not supported:
// NOT SUPPORTED - will produce an error
import public "other.fdl";
import weak "other.fdl";