When you're building an application, data rarely exists in isolation. Orders belong to customers. Posts have authors. Tasks are assigned to users. These relationships are fundamental to how applications work.
Today, we're sharing a preview of a major enhancement coming to Centrali: first-class record relationships with validation, cascade behaviors, and automatic expansion.
The Challenge Today
Currently, when you need to link records across structures, you store reference IDs manually:
{
"name": "orders",
"properties": [
{ "name": "customerId", "type": "string" },
{ "name": "productIds", "type": "array", "items": { "type": "string" } }
]
}This works, but has limitations:
- No validation — Nothing prevents storing an ID that doesn't exist
- Orphaned references — Delete a customer, and all orders pointing to them become broken
- Manual population — You need Smart Queries to fetch related data
- No cascade behavior — Deleting related records requires manual cleanup
What We're Building
A native reference property type that solves these problems while maintaining the flexibility you expect from Centrali.
Reference Property Type
Define relationships directly in your structure schema:
{
"name": "orders",
"properties": [
{
"name": "customer",
"type": "reference",
"target": "customers",
"displayField": "name",
"required": true,
"onDelete": "restrict"
},
{
"name": "lineItems",
"type": "reference",
"target": "products",
"isArray": true,
"onDelete": "set_null"
}
]
}Validated References
When you create or update a record, Centrali will verify that referenced records actually exist:
# This fails with a clear error if the customer doesn't exist
POST /structures/orders/records
{ "customer": "cust-invalid-123", "total": 99.99 }{
"error": "Reference validation failed",
"details": [
{
"field": "customer",
"message": "Referenced record 'cust-invalid-123' not found in 'customers'"
}
]
}No more orphaned references. No more silent data corruption.
Cascade Behaviors
Control what happens when a referenced record is deleted:
restrict— Prevent deletion if other records reference this onecascade— Automatically delete all records that reference this oneset_null— Set the reference field to null in referencing records
Example: Restrict deletion
# Attempting to delete a customer with orders
DELETE /structures/customers/records/cust-123{
"error": "Cannot delete record",
"message": "Record is referenced by 5 records in 'orders'",
"referencedBy": [
{ "structure": "orders", "count": 5 }
]
}This protects your data integrity automatically.
Automatic Expansion
Fetch related data inline without writing Smart Queries:
GET /structures/orders/records?expand=customer{
"records": [
{
"id": "order-123",
"total": 99.99,
"customer": "cust-456",
"_expanded": {
"customer": {
"id": "cust-456",
"name": "Acme Corp",
"email": "billing@acme.com"
}
}
}
]
}Nested expansion will also be supported:
GET /structures/orders/records?expand=customer,lineItems.categoryArray References
Link to multiple records for many-to-many relationships:
{
"name": "tags",
"type": "reference",
"target": "tags",
"isArray": true,
"onDelete": "set_null"
}{
"id": "post-123",
"title": "My Blog Post",
"tags": ["tag-1", "tag-2", "tag-3"]
}Use Cases
E-commerce
customers ←── orders (onDelete: restrict)
│
└──→ products (lineItems, isArray, onDelete: set_null)- Can't delete a customer with pending orders
- Order line items reference products directly
- If a product is deleted, line items become null (order preserved)
Content Management
authors ←── posts (onDelete: restrict)
│
└──→ categories (isArray, onDelete: set_null)- Authors can't be deleted while they have posts
- Posts can have multiple categories
- If a category is deleted, posts keep their other categories
Project Management
projects ←── tasks (onDelete: cascade)
│
└──→ users (assignee, onDelete: set_null)- Delete a project, all its tasks are deleted
- Delete a user, tasks become unassigned (not deleted)
What This Means for You
Backward Compatible
Your existing data continues to work unchanged. The new reference type is additive:
- Existing string fields storing IDs remain functional
- Smart Queries continue to work for complex joins
- Migrate to
referencetype when you're ready
Complements Smart Queries
This doesn't replace Smart Queries—it complements them. Use references for:
- Simple one-to-one and one-to-many relationships
- Data integrity enforcement
- Convenient auto-expansion
Continue using Smart Queries for:
- Complex multi-join queries
- Aggregations across structures
- Advanced filtering on joined data
Timeline
We're targeting Q1 2026 for this feature. The rollout will be phased:
- Phase 1: Reference property type with validation
- Phase 2:
?expand=query parameter for auto-population - Phase 3: Cascade behaviors (restrict, cascade, set_null)
- Phase 4: Console UI support for defining relationships visually
We Want Your Feedback
Before we finalize the design, we'd love to hear from you:
- What cascade behaviors matter most for your use case?
- What relationship patterns do you need that we haven't covered?
- Any edge cases we should consider?
Email us at feedback@centrali.io — we read every message.
This is part of our commitment to making Centrali the most developer-friendly backend platform. We're building the features you need to ship faster and maintain cleaner data.
Stay tuned for updates as we progress toward release.