Schema Reference Guide
Note: API-style reference for defining schemas. For a conceptual overview, patterns, and best practices, see Database Schema & Relationships Guide.
Table of Contents
- Introduction
- Schema Structure
- Field Types
- Field Properties
- Relationships
- Schema Properties
- Indexing
- Default Values
- Examples
- Best Practices
Introduction
In BAASIX, schemas define the structure of your data collections. A schema specifies the fields, their types, relationships between collections, and other properties that determine how data is stored and validated.
Schema Structure
A schema definition contains the following key components:
{
"collectionName": "products",
"schema": {
"name": "Product",
"timestamps": true,
"paranoid": true,
"freezeTableName": true,
"fields": {
// Field definitions go here
},
"indexes": [
// Index definitions go here
]
}
}| Property | Type | Description |
|---|---|---|
| collectionName | string | Name of the database collection/table |
| schema | object | Object containing the schema definition |
| schema.name | string | Display name of the schema |
| schema.timestamps | boolean | Add createdAt and updatedAt fields automatically (default: true) |
| schema.paranoid | boolean | Enable soft deletes with deletedAt field (default: false) |
| schema.freezeTableName | boolean | Prevent pluralization of table name (default: false) |
| schema.fields | object | Object containing field definitions |
| schema.indexes | array | Array of index definitions |
Field Types
BAASIX supports the following field types. For a complete guide on filtering these types, see Complete Filter Reference.
Supported Field Type Categories:
- String Types: String, Text, CiText, TOKEN
- Numeric Types: Integer, BigInt, Real, Double, Decimal
- Date/Time Types: DateTime, DateTime_NO_TZ, Date, Time, Time_NO_TZ
- Other Basic Types: Boolean, JSON, JSONB, UUID, ENUM
- Array Types: Array_Integer, Array_String, Array_Double, Array_Decimal, Array_DateTime, Array_DateTime_NO_TZ, Array_Date, Array_Time, Array_Time_NO_TZ, Array_UUID, Array_Boolean
- Range Types: Range_Integer, Range_DateTime, Range_DateTime_NO_TZ, Range_Date, Range_Decimal, Range_Double, Range_Time, Range_Time_NO_TZ
- PostGIS Types: Point, LineString, Polygon, MultiPoint, MultiLineString, MultiPolygon, GeometryCollection, Geography
- Computed Types: VIRTUAL
String Types
| Type | Description | Example Value | Configuration |
|---|---|---|---|
| String | Variable-length string (default 255) | "Hello world" | values.stringLength for custom length |
| Text | Unlimited-length text | "Long paragraph of text..." | - |
| TEXT | Alias for Text | "Long paragraph of text..." | - |
| CiText | Case-insensitive text (requires citext extension) | "hello" matches "HELLO" | - |
| TOKEN | 9-character unique string token | "ABC123XYZ" | Auto-generated |
Numeric Types
| Type | Description | Example Value | Configuration |
|---|---|---|---|
| Integer | 32-bit signed integer | 42 | - |
| BigInt | 64-bit signed integer | 9007199254740991 | - |
| Real | Single-precision floating-point | 3.14 | - |
| Double | Double-precision floating-point | 3.141592653589793 | - |
| DOUBLE | Alias for Double | 3.141592653589793 | - |
| Decimal | Arbitrary precision decimal | 123.45 | values.precision, values.scale |
Date/Time Types
Timezone Pattern: Base types include timezone; append _NO_TZ for types without timezone.
| Type | PostgreSQL Type | Description | Example Value |
|---|---|---|---|
| DateTime | timestamp with time zone | Timestamp WITH timezone | "2023-06-01T14:30:00Z" |
| DateTime_NO_TZ | timestamp | Timestamp WITHOUT timezone | "2023-06-01T14:30:00" |
| Date | date | Date only (no time) | "2023-06-01" |
| Time | time with time zone | Time WITH timezone | "14:30:00+05:30" |
| Time_NO_TZ | time | Time WITHOUT timezone | "14:30:00" |
Other Basic Types
| Type | Description | Example Value |
|---|---|---|
| Boolean | True/false value | true |
| JSON | Standard JSON type | {"key": "value"} |
| JSONB | Binary JSON (more efficient) | {"key": "value"} |
| UUID | Universally unique identifier | "550e8400-e29b-41d4-a716-446655440000" |
| ENUM | Predefined list of values | "active" (stored as varchar) |
Array Types (PostgreSQL Arrays)
For filtering array fields, see Complete Filter Reference - Array Operators.
| Type | Description | Example Value |
|---|---|---|
| Array_Integer | Array of integers | [1, 2, 3, 4, 5] |
| Array_String | Array of strings/text | ["red", "green", "blue"] |
| Array_Double | Array of doubles | [1.5, 2.7, 3.9] |
| Array_Decimal | Array of decimals | [10.50, 20.75, 30.25] |
| Array_DateTime | Array of timestamps WITH TZ | ["2023-01-01T00:00:00Z", ...] |
| Array_DateTime_NO_TZ | Array of timestamps WITHOUT TZ | ["2023-01-01T00:00:00", ...] |
| Array_Date | Array of dates (date only) | ["2023-01-01", "2023-02-01"] |
| Array_Time | Array of times WITH TZ | ["14:30:00+05:30", ...] |
| Array_Time_NO_TZ | Array of times WITHOUT TZ | ["14:30:00", "15:45:00"] |
| Array_UUID | Array of UUIDs | ["uuid1", "uuid2"] |
| Array_Boolean | Array of booleans | [true, false, true] |
Range Types (PostgreSQL Ranges)
Range types store lower/upper bounds with inclusivity flags. For filtering range fields, see Complete Filter Reference.
| Type | PostgreSQL Type | Description | Example Value |
|---|---|---|---|
| Range_Integer | int4range | Integer range | {"lower": 1, "upper": 10} |
| Range_DateTime | tstzrange | Timestamp range WITH timezone | {"lower": "2023-01-01T00:00:00Z", ...} |
| Range_DateTime_NO_TZ | tsrange | Timestamp range WITHOUT timezone | {"lower": "2023-01-01T00:00:00", ...} |
| Range_Date | daterange | Date range (date only) | {"lower": "2023-01-01", "upper": "2023-12-31"} |
| Range_Decimal | numrange | Numeric/decimal range | {"lower": 10.5, "upper": 100.5} |
| Range_Double | numrange | Double precision range | {"lower": 1.5, "upper": 99.9} |
| Range_Time | timetzrange | Time range WITH timezone | {"lower": "09:00:00+05:30", ...} |
| Range_Time_NO_TZ | timerange | Time range WITHOUT timezone | {"lower": "09:00:00", "upper": "17:00:00"} |
Range Value Structure:
{
"lower": "value", // Lower bound
"upper": "value", // Upper bound
"lowerInclusive": true, // Include lower bound (default: true)
"upperInclusive": true // Include upper bound (default: true)
}PostGIS Geometry Types (requires PostGIS extension)
For geospatial filtering (within, contains, intersects, dwithin), see Complete Filter Reference - Geospatial Operators.
| Type | Description | Example Value |
|---|---|---|
| Point | Single point in 2D space | {"type": "Point", "coordinates": [lng, lat]} |
| LineString | Line in 2D space | {"type": "LineString", "coordinates": [[lng1,lat1], [lng2,lat2]]} |
| Polygon | Polygon in 2D space | {"type": "Polygon", "coordinates": [[[lng1,lat1], ...]]} |
| MultiPoint | Multiple points | {"type": "MultiPoint", "coordinates": [[lng1,lat1], ...]} |
| MultiLineString | Multiple line strings | {"type": "MultiLineString", ...} |
| MultiPolygon | Multiple polygons | {"type": "MultiPolygon", ...} |
| GeometryCollection | Collection of mixed geometries | {"type": "GeometryCollection", ...} |
| Geography | Geographic data (Earth spheroid) | GeoJSON format |
PostGIS Configuration: Use values.srid to set Spatial Reference System ID (default: 4326 for WGS84).
Computed/Virtual Types
| Type | Description | Configuration |
|---|---|---|
| VIRTUAL | Computed field with SQL expression | Requires calculated property with SQL expression |
Virtual Field Example:
{
"fullName": {
"type": "VIRTUAL",
"calculated": "CONCAT(\"firstName\", ' ', \"lastName\")"
}
}Field Type Examples
{
"fields": {
"id": {
"type": "UUID",
"primaryKey": true,
"defaultValue": {
"type": "UUIDV4"
}
},
"name": {
"type": "String",
"allowNull": false,
"length": 100
},
"description": {
"type": "Text"
},
"price": {
"type": "Decimal",
"values": {
"precision": 10,
"scale": 2
}
},
"status": {
"type": "Enum",
"values": ["draft", "published", "archived"],
"defaultValue": "draft"
},
"tags": {
"type": "Array",
"itemType": "String"
}
}
}Field Properties
Each field can have various properties that define its behavior:
| Property | Type | Description |
|---|---|---|
| type | string | The data type of the field |
| allowNull | boolean | Whether the field can be null (default: true) |
| unique | boolean | Whether the field must be unique (default: false) |
| primaryKey | boolean | Whether the field is the primary key (default: false) |
| autoIncrement | boolean | Auto-increment integer field (default: false) |
| defaultValue | various | Default value if none is provided |
| values | object/array | Additional values for types like Enum or Decimal |
| length | number | Maximum length for String type |
| comment | string | Comment/description for the field |
| validate | object | Validation rules for the field |
| hidden | boolean | Hide this field in API responses (default: false) |
| immutable | boolean | Field cannot be updated after creation (default: false) |
| description | string | Human-readable description of the field |
Validation Examples
{
"fields": {
"email": {
"type": "String",
"validate": {
"isEmail": true,
"notEmpty": true
}
},
"age": {
"type": "Integer",
"validate": {
"min": 18,
"max": 99
}
},
"website": {
"type": "String",
"validate": {
"isUrl": true
}
},
"zipCode": {
"type": "String",
"validate": {
"matches": "^\\d{5}(-\\d{4})?$"
}
}
}
}Relationships
BAASIX supports the following relationship types:
One-to-Many (hasMany/belongsTo)
{
"fields": {
"id": {
"type": "UUID",
"primaryKey": true
},
"name": {
"type": "String"
},
// Foreign key for the belongsTo relationship
"category_id": {
"type": "UUID",
"allowNull": true
},
// Relationship definition
"category": {
"relType": "BelongsTo",
"target": "categories",
"foreignKey": "category_id",
"as": "category",
"onDelete": "SET NULL"
},
"products": {
"relType": "HasMany",
"target": "products",
"foreignKey": "category_id",
"as": "products"
}
}
}Many-to-Many (belongsToMany)
{
"fields": {
"id": {
"type": "UUID",
"primaryKey": true
},
"name": {
"type": "String"
},
"tags": {
"relType": "BelongsToMany",
"target": "tags",
"through": "product_tags",
"foreignKey": "product_id",
"otherKey": "tag_id",
"as": "tags"
}
}
}One-to-One (hasOne/belongsTo)
{
"fields": {
"id": {
"type": "UUID",
"primaryKey": true
},
"user_id": {
"type": "UUID",
"allowNull": false,
"unique": true
},
"user": {
"relType": "BelongsTo",
"target": "baasix_User",
"foreignKey": "user_id",
"as": "user"
},
"profile": {
"relType": "HasOne",
"target": "profiles",
"foreignKey": "user_id",
"as": "profile"
}
}
}Relationship Properties
| Property | Type | Description |
|---|---|---|
| relType | string | Type of relationship (BelongsTo, HasMany, etc.) |
| target | string | Target collection name |
| foreignKey | string | Foreign key field name |
| otherKey | string | Other key in many-to-many relationships |
| through | string | Junction table for many-to-many relationships |
| as | string | Alias for the relationship |
| onDelete | string | Action on delete (CASCADE, SET NULL, etc.) |
| onUpdate | string | Action on update (CASCADE, RESTRICT, etc.) |
Schema Properties
Additional properties you can set at the schema level:
Timestamps
When timestamps: true is set, the following fields are automatically added:
{
"createdAt": {
"type": "DateTime",
"allowNull": false
},
"updatedAt": {
"type": "DateTime",
"allowNull": false
}
}Paranoid (Soft Delete)
When paranoid: true is set, the following field is added:
{
"deletedAt": {
"type": "DateTime",
"allowNull": true
}
}Records with a non-null deletedAt value are excluded from normal queries.
Indexing
Define indexes to optimize query performance:
{
"schema": {
"fields": {
// Field definitions
},
"indexes": [
{
"name": "products_name_idx",
"fields": ["name"]
},
{
"name": "products_category_status_idx",
"fields": ["category_id", "status"]
},
{
"name": "products_price_idx",
"fields": [["price", "DESC"]]
},
{
"name": "products_description_fulltext",
"type": "FULLTEXT",
"fields": ["description"]
},
{
"name": "products_created_at_idx",
"method": "BTREE",
"fields": ["createdAt"]
},
{
"name": "products_location_geo_idx",
"type": "SPATIAL",
"fields": ["location"]
}
]
}
}Index Properties
| Property | Type | Description |
|---|---|---|
| name | string | Name of the index |
| fields | array | Fields to index |
| type | string | Index type (BTREE, HASH, GIST, FULLTEXT, SPATIAL, etc.) |
| unique | boolean | Whether the index enforces uniqueness (default: false) |
| method | string | Index method (database-specific) |
Default Values
You can set default values for fields in multiple ways:
Static Default Value
{
"status": {
"type": "String",
"defaultValue": "active"
},
"isVerified": {
"type": "Boolean",
"defaultValue": false
},
"score": {
"type": "Integer",
"defaultValue": 0
}
}Function Default Value
{
"id": {
"type": "UUID",
"primaryKey": true,
"defaultValue": {
"type": "UUIDV4"
}
},
"createdAt": {
"type": "DateTime",
"defaultValue": {
"type": "NOW"
}
}
}Supported Default Value Types
| Type | Description |
|---|---|
| NOW | Current date and time |
| UUIDV4 | Version 4 UUID (random) |
| AUTOINCREMENT | Auto-incrementing integer |
| SQL | Custom SQL expression |
| SUID | Short unique ID |
SQL Default Value Example:
{
"sortOrder": {
"type": "Integer",
"defaultValue": {
"type": "SQL",
"value": "(SELECT COALESCE(MAX(sort_order), 0) + 1 FROM products)"
}
}
}Examples
Complete Product Schema Example
{
"collectionName": "products",
"schema": {
"name": "Product",
"timestamps": true,
"paranoid": true,
"fields": {
"id": {
"type": "UUID",
"primaryKey": true,
"defaultValue": {
"type": "UUIDV4"
},
"description": "Unique identifier for the product"
},
"name": {
"type": "String",
"allowNull": false,
"length": 100,
"validate": {
"notEmpty": true
},
"description": "Product name"
},
"slug": {
"type": "String",
"unique": true,
"allowNull": false,
"description": "URL-friendly product identifier"
},
"description": {
"type": "Text",
"description": "Detailed product description"
},
"price": {
"type": "Decimal",
"allowNull": false,
"values": {
"precision": 10,
"scale": 2
},
"validate": {
"min": 0
},
"description": "Product price"
},
"status": {
"type": "Enum",
"values": ["draft", "active", "archived"],
"defaultValue": "draft",
"description": "Current product status"
},
"featured": {
"type": "Boolean",
"defaultValue": false,
"description": "Whether the product is featured"
},
"inventory": {
"type": "Integer",
"defaultValue": 0,
"validate": {
"min": 0
},
"description": "Current inventory level"
},
"metadata": {
"type": "JSON",
"description": "Additional product metadata"
},
"tags": {
"type": "Array",
"itemType": "String",
"description": "Product tags"
},
"category_id": {
"type": "UUID",
"allowNull": true,
"description": "Foreign key for category"
},
"category": {
"relType": "BelongsTo",
"target": "categories",
"foreignKey": "category_id",
"as": "category",
"onDelete": "SET NULL",
"description": "Product category"
},
"images": {
"relType": "HasMany",
"target": "product_images",
"foreignKey": "product_id",
"as": "images",
"description": "Product images"
}
},
"indexes": [
{
"name": "products_name_idx",
"fields": ["name"]
},
{
"name": "products_status_featured_idx",
"fields": ["status", "featured"]
},
{
"name": "products_price_idx",
"fields": [["price", "DESC"]]
},
{
"name": "products_description_fulltext",
"type": "FULLTEXT",
"fields": ["description"]
}
]
}
}User Authentication Schema Example
{
"collectionName": "users",
"schema": {
"name": "User",
"timestamps": true,
"fields": {
"id": {
"type": "UUID",
"primaryKey": true,
"defaultValue": {
"type": "UUIDV4"
}
},
"email": {
"type": "String",
"allowNull": false,
"unique": true,
"validate": {
"isEmail": true
}
},
"password": {
"type": "String",
"allowNull": false,
"hidden": true
},
"firstName": {
"type": "String",
"allowNull": false
},
"lastName": {
"type": "String",
"allowNull": false
},
"role_id": {
"type": "UUID",
"allowNull": false
},
"role": {
"relType": "BelongsTo",
"target": "baasix_Role",
"foreignKey": "role_id",
"as": "role"
},
"isActive": {
"type": "Boolean",
"defaultValue": true
},
"lastLogin": {
"type": "DateTime",
"allowNull": true
},
"profile": {
"relType": "HasOne",
"target": "user_profiles",
"foreignKey": "user_id",
"as": "profile"
}
}
}
}Best Practices
- Use UUID Primary Keys: UUIDs help prevent predictable IDs and are more suitable for distributed systems.
- Apply Proper Validation: Define validation rules to ensure data integrity.
- Include Descriptive Comments: Use the
descriptionfield to document the purpose of each field. - Consider Indexing Performance: Only create indexes for fields that are frequently queried.
- Use Relationships Properly: Define relationships to maintain data consistency and enable efficient querying.
- Implement Soft Deletes: Use the
paranoidoption for collections where data should be preserved even after deletion. - Be Consistent with Naming: Follow a consistent naming pattern for fields and relationships.
- Set Default Values: Provide sensible defaults to ensure data consistency.
- Add Constraints: Use
allowNull,unique, and validation rules to enforce data integrity. - Design with Future Changes in Mind: Create flexible schemas that can accommodate future changes.
Related Documentation
- Database Schema Guide - Conceptual overview, patterns, and best practices
- Schema Routes API - API endpoints for schema management
- Item Routes API - API endpoints for data operations
- Item Query Reference Guide - Query language for data retrieval
- Complete Filter Reference - All filter operators including array, range, and geospatial
- Advanced Query Guide - Complex filtering, aggregation, and spatial queries