Data Types

Database-agnostic data types with automatic SQL mapping per database

DataTypes Enum

typescript
import { DataTypes } from "stabilize-orm";
DataTypes.STRING // VARCHAR - short text with optional length
DataTypes.TEXT // TEXT - long text content
DataTypes.INTEGER // INTEGER - whole numbers
DataTypes.BIGINT // BIGINT - large whole numbers
DataTypes.FLOAT // FLOAT - single-precision decimal
DataTypes.DOUBLE // DOUBLE - double-precision decimal
DataTypes.DECIMAL // DECIMAL - exact decimal (e.g. currency)
DataTypes.BOOLEAN // BOOLEAN - true/false values
DataTypes.DATE // DATE - date only
DataTypes.DATETIME // DATETIME - date and time
DataTypes.JSON // JSON - JSON data
DataTypes.UUID // UUID - universally unique identifier
DataTypes.BLOB // BLOB - binary data

Database Type Mappings

DataTypePostgreSQLMySQLSQLiteSQL Server
DataTypes.STRINGTEXTVARCHAR(255)TEXTNVARCHAR(255)
DataTypes.TEXTTEXTTEXTTEXTNVARCHAR(MAX)
DataTypes.INTEGERINTEGERINTINTEGERINT
DataTypes.BIGINTBIGINTBIGINTINTEGERBIGINT
DataTypes.FLOATREALFLOATREALREAL
DataTypes.DOUBLEDOUBLE PRECISIONDOUBLEREALFLOAT
DataTypes.DECIMALDECIMAL(10,2)DECIMAL(10,2)NUMERICDECIMAL(10,2)
DataTypes.BOOLEANBOOLEANTINYINT(1)INTEGERBIT
DataTypes.DATEDATEDATETEXTDATE
DataTypes.DATETIMETIMESTAMPDATETIMETEXTDATETIME2
DataTypes.JSONJSONBJSONTEXTNVARCHAR(MAX)
DataTypes.UUIDUUIDCHAR(36)TEXTUNIQUEIDENTIFIER
DataTypes.BLOBBYTEABLOBBLOBVARBINARY(MAX)

String Types

DataTypes.STRING→ TEXT / VARCHAR(255) / TEXT

Variable-length string. Note that PostgreSQL maps this to TEXT rather than a length-capped VARCHAR — the length option does not produce a PostgreSQL length constraint, because Postgres treats TEXT and VARCHAR(n) as the same type. It is still enforced: the value is checked against the declared length on write.

typescript
{ type: DataTypes.STRING, length: 255 }
DataTypes.TEXT→ TEXT

Large text content with no length limit. Identical to STRING at the SQL level, but expresses intent.

typescript
{ type: DataTypes.TEXT }

Numeric Types

DataTypes.INTEGER→ INTEGER / INT / INTEGER

Whole numbers.

typescript
{ type: DataTypes.INTEGER }
DataTypes.BIGINT→ BIGINT / BIGINT / INTEGER

Large whole numbers. SQLite has no distinct 64-bit type, so it falls back to INTEGER.

typescript
{ type: DataTypes.BIGINT }
DataTypes.FLOAT→ REAL / FLOAT / REAL

Single-precision floating-point numbers.

typescript
{ type: DataTypes.FLOAT }
DataTypes.DOUBLE→ DOUBLE PRECISION / DOUBLE / REAL

Double-precision floating-point numbers.

typescript
{ type: DataTypes.DOUBLE }
DataTypes.DECIMAL→ DECIMAL(10,2) / NUMERIC

Exact decimal numbers — use this for money. Unlike FLOAT/DOUBLE it stores the value you wrote rather than the nearest binary approximation.

typescript
{ type: DataTypes.DECIMAL, precision: 10, scale: 2 }

Boolean Type

DataTypes.BOOLEAN→ BOOLEAN / TINYINT(1) / INTEGER

True/false values.

typescript
{ type: DataTypes.BOOLEAN, defaultValue: false }

Date & Time Types

DataTypes.DATETIME→ TIMESTAMP / DATETIME / TEXT

Date and time.

typescript
{ type: DataTypes.DATETIME }
DataTypes.DATE→ DATE / DATE / TEXT

Date only, no time component.

typescript
{ type: DataTypes.DATE }

There is no DataTypes.TIME. The enum stops at these two temporal types — store a time of day as a STRING or fold it into a DATETIME. SQLite stores both temporal types as TEXT, so a comparison there is a string comparison; an ISO-8601 value is the safe format to write.

Special Types

DataTypes.JSON→ JSONB / JSON / TEXT

JSON data. PostgreSQL uses JSONB, which is stored decomposed and can be indexed.

typescript
{ type: DataTypes.JSON }
DataTypes.UUID→ UUID / CHAR(36) / TEXT

Universally unique identifier. Only PostgreSQL has a native type; MySQL and SQLite store the string form.

typescript
import { generateUUID } from "stabilize-orm";
{ type: DataTypes.UUID, defaultValue: generateUUID() }
DataTypes.BLOB→ BYTEA / BLOB / BLOB

Binary large object — files, images, raw bytes.

typescript
{ type: DataTypes.BLOB }

Primary Keys

There is no primaryKey or autoIncrement column option. The column keyed id is always the primary key, and the DDL chosen for it depends only on its type:

typescript
columns: {
// Integer-style id → the dialect's auto-increment primary key
id: { type: DataTypes.INTEGER },
// STRING or UUID id → a client-supplied primary key, no auto-increment
id: { type: DataTypes.UUID, required: true },
}
id typeGenerated DDL
INTEGER / BIGINT / otherSERIAL PRIMARY KEY (Postgres) · INT AUTO_INCREMENT PRIMARY KEY (MySQL) · INTEGER PRIMARY KEY AUTOINCREMENT (SQLite) · INT IDENTITY(1,1) PRIMARY KEY (SQL Server)
STRINGUUID PRIMARY KEY (Postgres) · VARCHAR(255) PRIMARY KEY (MySQL) · TEXT PRIMARY KEY (SQLite) · NVARCHAR(255) PRIMARY KEY (SQL Server)
UUIDUUID PRIMARY KEY (Postgres) · VARCHAR(255) PRIMARY KEY (MySQL) · TEXT PRIMARY KEY (SQLite) · UNIQUEIDENTIFIER PRIMARY KEY (SQL Server)

Because the primary key is recognised by the column key id, a model that names it anything else gets no primary key at all.

Complete Example

models/Product.ts
import { defineModel, DataTypes } from "stabilize-orm";
const Product = defineModel({
tableName: "products",
columns: {
id: { type: DataTypes.STRING, required: true, unique: true },
name: { type: DataTypes.STRING, length: 255, required: true },
description: { type: DataTypes.TEXT },
price: { type: DataTypes.DECIMAL, required: true },
stock: { type: DataTypes.INTEGER, defaultValue: 0 },
isActive: { type: DataTypes.BOOLEAN, defaultValue: true },
metadata: { type: DataTypes.JSON },
releaseDate: { type: DataTypes.DATE },
createdAt: { type: DataTypes.DATETIME },
},
});