Scalar types

Every .forge scalar type with its Rust and TypeScript mapping, storage layout, and index/filter/sort behavior.

These are the primitive types a field can hold. For composite types (relations, arrays, inline structs) see relations; for closed value sets see enums.

The complete list#

TypeRustTypeScriptStorageIndexable / filterable / sortable
u32u32numberfixed 4-byte column
u64u64numberfixed 8-byte column
i32i32numberfixed 4-byte column
i64i64numberfixed 8-byte column
f64f64numberfixed 8-byte column✅ (filter/sort; ordered index deferred)
boolboolbooleanfixed 1-byte column
stringStringstringvariable-length column
jsonserde_json::Valueunknownvariable-length column (serialized JSON)
decimalrust_decimal::Decimalstringfixed 16-byte column
uuiduuid::Uuidstringfixed 16-byte column
timestampi64numberfixed 8-byte column
char(N)[u8; N]stringfixed N-byte column

There is no `text` type

Older docs mention a text type. It does not exist — use string for all variable-length UTF-8 text. Likewise the ~ auto-update modifier does not exist.

Integers, floats, and booleans#

u32/u64/i32/i64 are unsigned/signed integers; f64 is a 64-bit float; bool is true/false. All ride fixed-width columns and are indexable, filterable, and sortable.

f64 is filterable and sortable, but does not yet get an ordered/range index: floats have no clean total order, since NaN breaks Ord. Equality filters and sorting still work.

string#

Variable-length UTF-8 text, stored on the variable-length column. Indexable, filterable, and sortable. A hash index on a string is exact-match only (see indexes).

char(N)#

A fixed-size byte array of exactly N bytes ([u8; N] in Rust). Being fixed-width, it can live inside a struct — where string cannot. Requires the parenthesized size: code: char(8).

uuid#

A universally unique identifier, stored on a fixed 16-byte column. Foreign-key columns are always uuid, which is why relation traversal is only generated between UUID-keyed models.

timestamp#

A Unix timestamp stored as an i64. Auto-generatable with + (fills the current time on insert).

json#

Arbitrary JSON, typed serde_json::Value in Rust and unknown in TypeScript. Its serialized bytes ride the same variable-length column as string.

`json` is not indexable, filterable, or sortable

JSON has no total order the generated closed-set matcher can key on, so ^/&, REST ?field= filter/sort, and find_by_* are all rejected on a json field. json? uses a 1-byte presence tag, so None and Some(Value::Null) round-trip distinctly.

decimal#

Exact fixed-point (rust_decimal::Decimal) for money and quantities where f64 would drift. It rides the fixed 16-byte column (like uuid) and serializes to and from JSON as a string (precision-preserving — TS types it string).

Because Decimal is Ord + Hash, decimal is filterable, sortable, and indexable. The index key is normalized (.normalize()), so scale-only differences like 1.0 and 1.00 share one bucket.

`decimal(p, s)` precision is deferred

Only bare decimal is parsed today. Precision/scale metadata (decimal(10, 2)) is not yet supported.

Nullability#

Any scalar can be made nullable with a postfix ? (age: i32?, bio: string?). Nullable fixed-width types carry a 1-byte presence tag so an absent value and a zero value stay distinct. See modifiers for the full nullability rules.

Search documentation

Find pages across the ForgeDB docs