Skip to Content
Apso is in public beta. Get started
GuidesSchemaField types

Field types

Every field in the version 2 .apsorc schema has a name and type. Choose types for the data contract first, then check how the selected framework and database represent them.

Portable type reference

TypeUseTypical generated type
textGeneral text with no fixed maximumstring
stringString alias used by imported schemasstring
varcharText with an optional lengthstring
integerWhole numbersnumber, int
floatFloating-point valuesnumber, float64
decimalFixed-precision numeric valuesFramework numeric type
numericPostgreSQL numeric aliasFramework numeric type
booleanTrue or falseboolean, bool
dateCalendar dateFramework date type
timestampTimestamp without timezoneFramework date-time type
timestamptzTimestamp with timezoneFramework date-time type
datetimeAlias normalized to timestampFramework date-time type
uuidUUID valuestring
enumOne value from a fixed setGenerated enum or string type
jsonStructured JSON valueObject, map, or any
json-plainJSON alias used by the TypeScript generatorObject or any
arrayString array in current templatesstring[], []string

For a schema that must generate cleanly in TypeScript, Python, and Go, prefer text, varchar, integer, float, decimal, numeric, boolean, date, timestamp, timestamptz, uuid, enum, json, and array. Run apso schema validate after changing the target language because a generator can warn about aliases it does not fully support.

Common examples

Text and identifiers

{ "name": "title", "type": "text" } { "name": "email", "type": "varchar", "length": 255, "is_email": true, "unique": true } { "name": "externalId", "type": "uuid", "index": true }

Use is_email only for format validation. Authentication and email ownership require a separate workflow.

Numbers and money

{ "name": "quantity", "type": "integer", "default": 1 } { "name": "score", "type": "float", "nullable": true } { "name": "amount", "type": "decimal", "precision": 12, "scale": 2 }

Use decimal or numeric for values that need fixed precision. Confirm how the generated framework serializes those values before performing currency arithmetic.

Dates and timestamps

{ "name": "dueDate", "type": "date", "nullable": true } { "name": "scheduledAt", "type": "timestamptz" }

Use created_at and updated_at on the entity for generated lifecycle timestamps. Use a field when the date belongs to the product model.

Enum

{ "name": "status", "type": "enum", "values": ["Draft", "Active", "Archived"], "default": "Draft" }

An enum requires a non-empty values array. The default must be one of those values.

JSON and arrays

{ "name": "settings", "type": "json", "nullable": true } { "name": "tags", "type": "array", "nullable": true }

Use JSON for provider payloads or configuration with genuinely variable structure. Define stable fields explicitly when you need to filter, relate, or validate them.

Field options

OptionTypeUse
nullablebooleanAllow the column to be absent or null.
uniquebooleanAdd a single-field unique constraint.
indexbooleanAdd an index for common filters or lookups.
defaultscalar or nullSet the generated database default.
lengthintegerSet a text length where the selected type supports it.
precisionintegerSet total digits for decimal or numeric.
scaleintegerSet digits after the decimal point. It cannot exceed precision.
is_emailbooleanAdd email-format validation to a text field.
primarybooleanMark an explicit field as primary when the model requires it.

For most entities, use the generated id and set primaryKeyType to serial or uuid on the entity.

Entity example

.apsorc (entity excerpt)
{ "name": "Invoice", "primaryKeyType": "uuid", "created_at": true, "updated_at": true, "fields": [ { "name": "number", "type": "varchar", "length": 40, "unique": true }, { "name": "status", "type": "enum", "values": ["Draft", "Open", "Paid"], "default": "Draft" }, { "name": "subtotal", "type": "decimal", "precision": 12, "scale": 2 }, { "name": "dueDate", "type": "date", "nullable": true }, { "name": "metadata", "type": "json", "nullable": true } ] }

Verify a type change

  1. Run apso schema validate.
  2. Run apso generate.
  3. Inspect the generated entity and request DTO.
  4. Run apso migrate and review the SQL.
  5. Test serialization through the REST endpoint and SDK.

Changing an existing field type can rewrite or reject stored data. Treat the migration output as a required review artifact and test it against representative data before deployment.

Last updated on