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
| Type | Use | Typical generated type |
|---|---|---|
text | General text with no fixed maximum | string |
string | String alias used by imported schemas | string |
varchar | Text with an optional length | string |
integer | Whole numbers | number, int |
float | Floating-point values | number, float64 |
decimal | Fixed-precision numeric values | Framework numeric type |
numeric | PostgreSQL numeric alias | Framework numeric type |
boolean | True or false | boolean, bool |
date | Calendar date | Framework date type |
timestamp | Timestamp without timezone | Framework date-time type |
timestamptz | Timestamp with timezone | Framework date-time type |
datetime | Alias normalized to timestamp | Framework date-time type |
uuid | UUID value | string |
enum | One value from a fixed set | Generated enum or string type |
json | Structured JSON value | Object, map, or any |
json-plain | JSON alias used by the TypeScript generator | Object or any |
array | String array in current templates | string[], []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
| Option | Type | Use |
|---|---|---|
nullable | boolean | Allow the column to be absent or null. |
unique | boolean | Add a single-field unique constraint. |
index | boolean | Add an index for common filters or lookups. |
default | scalar or null | Set the generated database default. |
length | integer | Set a text length where the selected type supports it. |
precision | integer | Set total digits for decimal or numeric. |
scale | integer | Set digits after the decimal point. It cannot exceed precision. |
is_email | boolean | Add email-format validation to a text field. |
primary | boolean | Mark 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
{
"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
- Run
apso schema validate. - Run
apso generate. - Inspect the generated entity and request DTO.
- Run
apso migrateand review the SQL. - 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.