Skip to content

Field Types

ConvergeDB supports a fixed set of field types. Scalar and fixed-length types are stored inline within the entity row. Variable-length types (arrays, VarString, VarBytes) use a two-zone layout where only the actual data is stored, avoiding wasted space.

ConvergeDB typeC# typeSize (bytes)Range
u8byte10 to 255
u16ushort20 to 65,535
u32uint40 to 4,294,967,295
u64ulong80 to 2^64-1
u128UInt128160 to 2^128-1
i8sbyte1-128 to 127
i16short2-32,768 to 32,767
i32int4-2^31 to 2^31-1
i64long8-2^63 to 2^63-1
f32float4IEEE 754 single
f64double8IEEE 754 double
boolbool1true or false

ConvergeDB offers two string storage strategies: variable-length (default) and fixed-length (opt-in).

string fields default to VarString storage. Only the actual UTF-8 byte length is stored, using the two-zone layout: a 4-byte directory entry in the fixed zone and packed byte data in the data zone.

[Field(0, MaxLength = 256)] public string Bio { get; set; }

This maps to VarString(256) on the server. A 20-character bio uses roughly 24 bytes, not 258.

For short, predictable strings (currency codes, tags, identifiers), you can opt into fixed-length inline storage with FixedLength = true. This reserves 2 + MaxLength bytes in every entity row regardless of actual content.

[Field(0, MaxLength = 4, FixedLength = true)] public string CurrencyCode { get; set; }

This maps to String(4) on the server. Every entity reserves 6 bytes (2-byte length prefix + 4 bytes).

Use VarString (default) whenUse FixedLength when
Content length varies widelyContent length is predictable and short
MaxLength is large (> ~32 bytes)MaxLength is small (< ~16 bytes)
Most entities use a fraction of MaxLengthMost entities use close to MaxLength

The same two strategies apply to byte[] fields.

[Field(0, MaxLength = 1024)] public byte[] Payload { get; set; }

Maps to VarBytes(1024). Only actual byte length is stored.

[Field(0, MaxLength = 16, FixedLength = true)] public byte[] Hash { get; set; }

Maps to Bytes(16). Reserves 2 + 16 = 18 bytes inline in every entity row.

ConvergeDB typeC# declarationStorageZone
VarString(max_len)[Field(N, MaxLength = X)] stringActual byte length onlyData zone
String(max_len)[Field(N, MaxLength = X, FixedLength = true)] string2 + max_len bytes alwaysFixed zone
VarBytes(max_len)[Field(N, MaxLength = X)] byte[]Actual byte length onlyData zone
Bytes(max_len)[Field(N, MaxLength = X, FixedLength = true)] byte[]2 + max_len bytes alwaysFixed zone

The maximum allowed value for MaxLength is 65,535 bytes. MaxLength is always in bytes, not characters (UTF-8 is variable-width).

Struct fields allow one level of nesting. Define a sub-struct with [ConvergenceStruct]:

[ConvergenceStruct]
public partial struct Position
{
[Field(0)] public float X { get; set; }
[Field(1)] public float Y { get; set; }
[Field(2)] public float Z { get; set; }
}

Sub-struct fields may only contain scalars, fixed-length strings, or fixed-length bytes. VarString, VarBytes, nested structs, and arrays within structs are not supported.

See Structs and Arrays for full details.

Array fields hold a variable number of elements up to a declared maximum:

[ConvergenceEntity("Inventory")]
public partial struct Inventory
{
[Field(0, MaxCount = 50)] public ulong[] SlotIds { get; set; }
public ReadOnlyMemory<byte> EntityId { get; init; }
}

Supported element types include all scalars, fixed-length strings, fixed-length bytes, and [ConvergenceStruct] types. Arrays of arrays are not supported.

The maximum element count is 1024. See Limits.

Fields that use variable-length storage (arrays, VarString, VarBytes) use a two-zone row layout:

  1. Fixed zone — scalars, fixed-length strings/bytes, structs, and a 4-byte directory entry per variable-length field. This zone has a constant size per kind.
  2. Data zone — packed variable-length data for arrays, VarString, and VarBytes. Only actual content is stored.

For kinds with no variable-length fields, the data zone is empty and there is zero overhead.

All fields default to zero bytes when an entity is created or when a new field is added to an existing kind. This means:

  • Numeric types default to 0
  • Booleans default to false
  • Strings default to empty ("")
  • Byte arrays default to empty
  • Arrays default to zero elements