Types
Sora type expressions are written as strings in schema fields.
Primitive Types
| Type | Meaning |
|---|---|
bool | Boolean value. |
i8 | 8-bit signed integer. |
u8 | 8-bit unsigned integer. |
i16 | 16-bit signed integer. |
u16 | 16-bit unsigned integer. |
i32 | 32-bit signed integer. |
u32 | 32-bit unsigned integer. |
i64 | 64-bit signed integer. |
f32 | 32-bit floating point value. |
f64 | 64-bit floating point value. |
string | UTF-8 string. |
duration | Non-negative duration written as units such as 500ms, 30s, 15m, 2h, 7d, or 1h 30m. Units must be ordered from largest to smallest: d, h, m, s, ms. Runtime data stores milliseconds. |
text | Localization text key. See Localization. |
Integer widths are validated by Sora before export. Some target languages do not have unsigned small integer types, so generated code may use a wider signed type while preserving the schema range.
[[tables.fields]]
name = "level"
type = "u16"
range = [1, 100]
Named Types
| Type | Example |
|---|---|
| Enum | enum<ItemType> |
| Struct | struct<ResourceCost> |
| Union | union<RewardAction> |
| Reference | ref<Item.id> |
References must point to the primary key of a mode = "map" table. Containers can wrap references, for example list<ref<Item.id>>.
[[tables.fields]]
name = "item_type"
type = "enum<ItemType>"
[[tables.fields]]
name = "price"
type = "struct<ResourceCost>"
parser = { kind = "tuple" }
Collections
| Type | Meaning |
|---|---|
list<T> | Ordered repeated values. |
set<T> | Unique repeated values. |
array<T,N> | Fixed-length repeated values. |
map<K,V> | Key/value pairs. |
optional<T> | Nullable or absent value. |
[[tables.fields]]
name = "tags"
type = "set<string>"
parser = { kind = "json" }
default = "[\"misc\"]"
[[tables.fields]]
name = "attributes"
type = "map<string,i32>"
parser = { kind = "map" }
Intervals
interval<T> stores one non-empty bounded interval together with the inclusivity of each bound. T can be any integer or floating-point primitive, duration, or datetime.
[[tables.fields]]
name = "recommended_level"
type = "interval<i32>"
default = "[1,10]"
Excel, CSV, and string defaults use standard mathematical interval notation. [ and ] include a bound; ( and ) exclude it:
| Value | Meaning |
|---|---|
[1,10] | 1 <= x <= 10 |
(1,10] | 1 < x <= 10 |
[1,10) | 1 <= x < 10 |
(1,10) | 1 < x < 10 |
Both bounds are required. Sora rejects a start greater than the end. Equal bounds are valid only when both are inclusive, because every other equal-bound combination is empty.
Structured TOML, JSON, and YAML data uses the canonical object representation:
recommended_level = { start = 1, end = 10, start_inclusive = false, end_inclusive = true }
Generated APIs preserve these four fields and add boundary-aware helpers, so business code can call contains and isSingleton/is_singleton instead of repeating open/closed-bound checks. Rust, C++, C#, TypeScript, Python, and Scala use an idiomatic generic SoraInterval<T> (or the language’s bracket form). Java, Kotlin, Go, Dart, Godot, and C emit concrete types such as SoraIntervalI32; JavaScript, Lua, and Erlang provide a shared runtime interval helper. The binary and structured wire shapes remain unchanged. Collections of intervals are supported; use JSON cell input for those collections.
Cell Examples
These examples show what a designer would put in an Excel or CSV cell:
| Field type | Parser | Cell value |
|---|---|---|
u16 | none | 1001 |
enum<ItemType> | none | Weapon |
list<i32> | none or split | 1,2,3 |
duration | none | 1h 30m |
interval<i32> | none | (1,100] |
interval<duration> | none | [500ms,2s) |
text | none | quest.1001.title |
set<string> | json | ["starter","melee"] |
struct<ResourceCost> | tuple | Gold,0,100 |
struct<ResourceCost> | columns | spread across cost_kind, cost_id, cost_count columns |
map<string,i32> | map | atk,10|hp,20 |
union<EventCondition> | json | {"type":"QuestCompleted","quest_id":5002} |
optional<ref<Item.id>> | none | empty cell or 1001 |
Field Rules
[[tables.fields]], [[structs.fields]], and [[unions.variants.fields]] share the common field properties. Table fields have extra table-only properties for derived values; those properties are invalid on struct fields and union variant fields. A table primary key is declared once on the table itself with key = "field_name".
Field presence is part of the type: optional<T> means the value may be absent or null, while every other type is required unless a default fills the missing value.
For TOML/JSON/YAML-style object inputs, a field can be absent from the object. For Excel and CSV, the column must exist in the header; an omitted cell, blank cell, or short CSV record is treated as an empty cell.
| Schema field | Object field absent | Excel/CSV cell empty |
|---|---|---|
type = "i32" | Validation error. | Validation error. |
type = "optional<i32>" | null. | null. |
type = "i32" plus default = "1" | 1. | 1. |
type = "optional<i32>" plus default = "1" | 1. | null. |
| Property | Applies To | Purpose |
|---|---|---|
name | all fields | Field name used in source data, validation errors, generated code, and exported runtime data. |
type | all fields | Type expression such as i32, struct<ResourceCost>, or list<union<RewardAction>>. |
default | all fields except derived fields | String value used when the source object field is absent or a required Excel/CSV cell is empty. |
comment | all fields | Description used in generated Excel headers. |
range | numeric fields, duration, and collection elements of those types | Inclusive numeric range, written as [min, max]. Duration ranges are milliseconds. |
length | string, list, set, array, map | Inclusive length range, written as [min, max]. |
parser | cell-based inputs and defaults | Cell parser hint. See Cell Parsers. |
groups | all fields | Declared groups that contain the field. Omitted fields inherit the project’s default groups. |
from | table fields only | Optional child-table source for a derived field. |
Defaults are written as strings because they are parsed through the same type-aware conversion path as source data.
from describes a field derived from matching rows in another table; see References and Derived Fields. Derived fields can be list<T>, T, or optional<T> and cannot declare default.