Skip to Content
🚀 APSO is now in public beta. Get started →
GuidesSchemaField Types

Field Types Reference

Every field in your .apsorc schema requires a type property that determines the database column type, TypeScript type, and auto-applied validation decorators. This page covers all supported field types with their generated TypeORM mappings and examples.

Core Types

text

Variable-length text data. The most common field type.

{ "name": "title", "type": "text" } { "name": "email", "type": "text", "length": 255, "is_email": true } { "name": "bio", "type": "text", "nullable": true }
Generated Code
TypeORM@Column({ type: 'text' })
TypeScriptstring
Validation@IsString(), @IsNotEmpty()

Additional options:

OptionEffect
"length": 255@Column({ type: 'text', length: 255 }) and @MaxLength(255)
"is_email": trueAdds @IsEmail() validation
"unique": true@Column({ unique: true })
"nullable": true@Column({ nullable: true }) and @IsOptional()

Example with all options:

{ "name": "email", "type": "text", "length": 255, "unique": true, "is_email": true }

Generates:

@Column({ type: 'text', length: 255, unique: true }) @IsString() @IsNotEmpty() @IsEmail() @MaxLength(255) email: string;

integer

Whole number values.

{ "name": "count", "type": "integer" } { "name": "sortOrder", "type": "integer", "default": 0 }
Generated Code
TypeORM@Column({ type: 'integer' })
TypeScriptnumber
Validation@IsNumber()

float

Floating-point number values.

{ "name": "latitude", "type": "float" } { "name": "score", "type": "float", "nullable": true }
Generated Code
TypeORM@Column({ type: 'float' })
TypeScriptnumber
Validation@IsNumber()

boolean

True/false values.

{ "name": "isActive", "type": "boolean", "default": true } { "name": "isVerified", "type": "boolean", "default": false }
Generated Code
TypeORM@Column({ type: 'boolean' })
TypeScriptboolean
Validation@IsBoolean()

decimal

Fixed-precision decimal numbers. Ideal for financial data where floating-point imprecision is unacceptable.

{ "name": "price", "type": "decimal", "precision": 10, "scale": 2, "default": 0 }
Generated Code
TypeORM@Column({ type: 'decimal', precision: 10, scale: 2 })
TypeScriptnumber
Validation@IsNumber()

Options:

OptionTypeDescription
precisioninteger (1-131072)Total number of digits
scaleinteger (0-16383)Number of digits after the decimal point

Example:

{ "name": "price", "type": "decimal", "precision": 10, "scale": 2, "default": 0, "nullable": false }

Generates:

@Column({ type: 'decimal', precision: 10, scale: 2, default: 0 }) @IsNumber() price: number;

numeric

Functionally identical to decimal. PostgreSQL treats decimal and numeric as the same type. Use whichever name you prefer.

{ "name": "bandwidth_gb", "type": "numeric", "precision": 10, "scale": 3, "default": 0 }
Generated Code
TypeORM@Column({ type: 'numeric', precision: 10, scale: 3 })
TypeScriptnumber
Validation@IsNumber()

date

Date values (without time component).

{ "name": "birthDate", "type": "date" } { "name": "expiresOn", "type": "date", "nullable": true }
Generated Code
TypeORM@Column({ type: 'date' })
TypeScriptDate
ValidationNone auto-applied

timestamptz

Timestamp with time zone. Use this for datetime values where you need both date and time, including timezone information.

{ "name": "scheduledAt", "type": "timestamptz" } { "name": "expiresAt", "type": "timestamptz", "nullable": true }
Generated Code
TypeORM@Column({ type: 'timestamptz' })
TypeScriptDate
ValidationNone auto-applied

Note: For auto-managed timestamp columns, use "created_at": true and "updated_at": true at the entity level instead of defining fields with timestamptz. See Entity Definition.


enum

A predefined set of allowed string values. Requires a values array.

{ "name": "status", "type": "enum", "values": ["Active", "Inactive", "Deleted"], "default": "Active" }
Generated Code
TypeORM@Column({ type: 'enum', enum: EntityFieldEnum })
TypeScriptGenerated enum type (e.g., ProjectStatusEnum)
ValidationNone (constrained by the enum type itself)

Apso generates a TypeScript enum in src/autogen/enums.ts with the naming convention {EntityName}{FieldName}Enum:

// For entity "Project", field "status" export enum ProjectStatusEnum { Active = "Active", Inactive = "Inactive", Deleted = "Deleted", }

The entity column references this enum:

@Column({ type: 'enum', enum: ProjectStatusEnum, default: 'Active' }) status: ProjectStatusEnum;

Important: The values array is required when type is "enum". Omitting it will cause a validation error during scaffolding.


json

Arbitrary JSON data, stored as PostgreSQL jsonb for efficient querying and indexing.

{ "name": "metadata", "type": "json" } { "name": "settings", "type": "json", "nullable": true }
Generated Code
TypeORM@Column('jsonb')
TypeScriptany (or typed by your extension code)
ValidationNone auto-applied

Tip: While the generated type is any, you can add type safety in your extension service or DTO by defining an interface for the expected JSON structure.


PostGIS Spatial Types

Apso supports the full suite of PostGIS spatial data types for geographic and geometric data. These types are powerful for location-based applications, mapping, geofencing, and spatial analysis.

Prerequisite: PostGIS spatial types require the PostGIS extension to be installed in your PostgreSQL database:

CREATE EXTENSION IF NOT EXISTS postgis; -- Verify installation SELECT PostGIS_Version();

Ensure PostGIS is available in all environments (development, staging, production) where your application runs.

point

A single point in 2D space (x, y coordinates).

{ "name": "location", "type": "point", "nullable": true }
Generated Code
TypeORM@Column({ type: 'point' }) with value transformer
TypeScript{ x: number, y: number }
ValidationNone auto-applied

The generated code includes a value transformer that converts between the TypeScript object format and PostgreSQL’s point representation:

@Column({ type: 'point', transformer: { to: (point: { x: number, y: number } | null) => { if (!point) return null; return `(${point.x},${point.y})`; }, from: (pgPoint: string | null) => { if (!pgPoint) return null; const [x, y] = pgPoint.substring(1, pgPoint.length - 1).split(','); return { x: parseFloat(x), y: parseFloat(y) }; } }, nullable: true }) location: { x: number, y: number };

linestring

A sequence of points forming a line.

{ "name": "route", "type": "linestring", "nullable": true }
Generated Code
TypeORM@Column({ type: 'linestring' }) with value transformer
TypeScriptSpatial type
ValidationNone auto-applied

polygon

A closed shape defined by one or more rings of points. The first ring is the outer boundary; subsequent rings define holes.

{ "name": "boundary", "type": "polygon", "nullable": true }
Generated Code
TypeORM@Column({ type: 'polygon' }) with value transformer
TypeScript{ coordinates: Array<Array<{ x: number, y: number }>> }
ValidationNone auto-applied

The generated transformer handles conversion to and from PostgreSQL’s WKT (Well-Known Text) format:

@Column({ type: 'polygon', transformer: { to: (polygon) => { if (!polygon) return null; const rings = polygon.coordinates.map(ring => { const coords = ring.map(coord => `${coord.x} ${coord.y}`).join(','); return `(${coords})`; }); return `POLYGON(${rings.join(',')})`; }, from: (pgPolygon) => { if (!pgPolygon) return null; // ... parses WKT back to coordinate arrays } }, nullable: true }) boundary: { coordinates: Array<Array<{ x: number, y: number }>> };

multipoint

A collection of points.

{ "name": "stops", "type": "multipoint", "nullable": true }
Generated Code
TypeORM@Column({ type: 'multipoint' })
TypeScriptSpatial type
ValidationNone auto-applied

multilinestring

A collection of linestrings.

{ "name": "routes", "type": "multilinestring", "nullable": true }
Generated Code
TypeORM@Column({ type: 'multilinestring' })
TypeScriptSpatial type
ValidationNone auto-applied

multipolygon

A collection of polygons.

{ "name": "territories", "type": "multipolygon", "nullable": true }
Generated Code
TypeORM@Column({ type: 'multipolygon' })
TypeScriptSpatial type
ValidationNone auto-applied

geometry

A generic geometry type that can store any geometry (point, line, polygon, etc.).

{ "name": "shape", "type": "geometry", "nullable": true }
Generated Code
TypeORM@Column({ type: 'geometry' }) with pass-through transformer
TypeScriptany
ValidationNone auto-applied
@Column({ type: 'geometry', transformer: { to: (geometry: any) => { if (!geometry) return null; return geometry; }, from: (pgGeometry: any) => { if (!pgGeometry) return null; return pgGeometry; } }, nullable: true }) shape: any;

geography

Similar to geometry but uses geographic coordinates (latitude/longitude) on a spherical model. Calculations account for the Earth’s curvature, making it more accurate for real-world distance and area computations.

{ "name": "position", "type": "geography", "nullable": true }
Generated Code
TypeORM@Column({ type: 'geography' })
TypeScriptSpatial type
ValidationNone auto-applied

geometrycollection

A collection of heterogeneous geometry objects.

{ "name": "features", "type": "geometrycollection", "nullable": true }
Generated Code
TypeORM@Column({ type: 'geometrycollection' })
TypeScriptSpatial type
ValidationNone auto-applied

Complete Type Mapping Reference

Apso TypeTypeORM ColumnPostgreSQL TypeTypeScript TypeAuto-Validation
text@Column({ type: 'text' })TEXTstring@IsString(), @IsNotEmpty()
integer@Column({ type: 'integer' })INTEGERnumber@IsNumber()
float@Column({ type: 'float' })FLOATnumber@IsNumber()
boolean@Column({ type: 'boolean' })BOOLEANboolean@IsBoolean()
decimal@Column({ type: 'decimal' })DECIMAL(p,s)number@IsNumber()
numeric@Column({ type: 'numeric' })NUMERIC(p,s)number@IsNumber()
date@Column({ type: 'date' })DATEDateNone
timestamptz@Column({ type: 'timestamptz' })TIMESTAMPTZDateNone
enum@Column({ type: 'enum', enum: ... })ENUM(...)Generated enumNone
json@Column('jsonb')JSONBanyNone
point@Column({ type: 'point' })POINT{ x, y }None
linestring@Column({ type: 'linestring' })LINESTRINGSpatialNone
polygon@Column({ type: 'polygon' })POLYGON{ coordinates }None
multipoint@Column({ type: 'multipoint' })MULTIPOINTSpatialNone
multilinestring@Column({ type: 'multilinestring' })MULTILINESTRINGSpatialNone
multipolygon@Column({ type: 'multipolygon' })MULTIPOLYGONSpatialNone
geometry@Column({ type: 'geometry' })GEOMETRYanyNone
geography@Column({ type: 'geography' })GEOGRAPHYSpatialNone
geometrycollection@Column({ type: 'geometrycollection' })GEOMETRYCOLLECTIONSpatialNone

Field Options Reference

These options apply across field types where relevant:

OptionTypeApplies ToGenerated Code
nullablebooleanAll types@Column({ nullable: true }) + @IsOptional()
uniquebooleanAll types@Column({ unique: true })
defaultstring, number, booleanAll types@Column({ default: value })
lengthintegertext@Column({ length: n }) + @MaxLength(n)
is_emailbooleantext@IsEmail()
valuesstring[]enum (required)@Column({ enum: [...] })
precisionintegerdecimal, numeric@Column({ precision: n })
scaleintegerdecimal, numeric@Column({ scale: n })

Practical Examples

User entity

{ "name": "User", "created_at": true, "updated_at": true, "fields": [ { "name": "email", "type": "text", "length": 255, "unique": true, "is_email": true }, { "name": "fullName", "type": "text", "nullable": true }, { "name": "role", "type": "enum", "values": ["User", "Admin", "SuperAdmin"], "default": "User" }, { "name": "isActive", "type": "boolean", "default": true }, { "name": "lastLoginAt", "type": "timestamptz", "nullable": true }, { "name": "preferences", "type": "json", "nullable": true } ] }

Financial record

{ "name": "Transaction", "created_at": true, "fields": [ { "name": "amount", "type": "decimal", "precision": 12, "scale": 2 }, { "name": "currency", "type": "text", "length": 3 }, { "name": "status", "type": "enum", "values": ["Pending", "Completed", "Failed", "Refunded"] }, { "name": "metadata", "type": "json", "nullable": true } ] }

Location-aware entity

{ "name": "Store", "created_at": true, "updated_at": true, "fields": [ { "name": "name", "type": "text" }, { "name": "address", "type": "text" }, { "name": "location", "type": "point", "nullable": true }, { "name": "deliveryZone", "type": "polygon", "nullable": true }, { "name": "isOpen", "type": "boolean", "default": true } ] }

Next Steps

Last updated on