Basefyio Data Engine
The Basefyio Data Engine is a document data plane that runs alongside your existing dedicated databases. Store flexible, schema-driven documents with nested objects, arrays, versioning, soft-delete, and automatic multi-tenant isolation.
The Data Engine supports two storage providers — a dedicated NoSQL store for production workloads and a database JSONB fallback for development. Both implement the same interface; your application code works identically regardless of which provider is active.
Key Features
- Schema-driven documents — Define entities with typed fields. Documents are validated against your schema on every write.
- Nested data — Objects inside objects, arrays of objects, repeatable sections. No flattening required.
- Document versioning — Every document carries a
_versionand_eventSequence. Optimistic concurrency viaIf-Match. - Soft delete — Deleted documents are recoverable. Query with
includeSoftDeletedto see them. - Multi-tenant isolation — Every query has
_projectIdinjected server-side. Project A can never read Project B's data. - Event system — Every write produces an outbox event:
document.created,document.updated,document.deleted. - Provider-agnostic — Switch between NoSQL store and database with a single environment variable.
Document Envelope
Every stored document carries these reserved fields automatically:
{
"_id": "patients::550e8400-e29b-41d4-a716-446655440000",
"_entity": "patients",
"_projectId": "prj_abc123",
"_schemaVersion": 1,
"_version": 5,
"_eventSequence": 5,
"_status": "active",
"_createdAt": "2026-06-09T10:00:00.000Z",
"_updatedAt": "2026-06-09T15:30:00.000Z",
"_createdBy": "user_456",
"_deletedAt": null,
"firstName": "John",
"lastName": "Smith",
"address": {
"city": "Istanbul",
"country": "TR"
}
}| Field | Type | Description |
|---|---|---|
_id | string | Unique document identifier |
_entity | string | Entity type name |
_projectId | string | Owning project (injected server-side, cannot be overridden) |
_schemaVersion | number | Schema version this document was written under |
_version | number | Optimistic concurrency token (CAS) |
_eventSequence | number | Monotonic counter per document (for offline sync) |
_status | string | active, draft, archived, deleted, or pending_approval |
_createdAt | ISO 8601 | Creation timestamp |
_updatedAt | ISO 8601 | Last modification timestamp |
_createdBy | string | User ID who created the document |
_deletedAt | ISO 8601 | null | Soft-delete timestamp (null if active) |
User schemas cannot define fields starting with _. The system rejects them with HTTP 422.
REST API
Base path: https://api.basefyio.com/v1/projects/:projectId
Entity Management
| Method | Path | Description |
|---|---|---|
GET | /entities | List all entity definitions |
POST | /entities | Create an entity definition |
GET | /entities/:entity | Get entity definition with fields and rules |
Document CRUD
| Method | Path | Description |
|---|---|---|
POST | /data/:entity | Create a document |
GET | /data/:entity | List/query documents (filter, sort, paginate) |
GET | /data/:entity/:id | Get document by ID |
PATCH | /data/:entity/:id | Partial update (merge fields) |
PUT | /data/:entity/:id | Full replacement |
DELETE | /data/:entity/:id | Soft delete |
Query Parameters
| Parameter | Type | Example |
|---|---|---|
filter | JSON string | {"status":"active","address.city":"Istanbul"} |
sort | JSON string | [{"path":"_createdAt","direction":"desc"}] |
limit | number | 50 (max 1000) |
offset | number | 0 |
SDK Usage
import { createClient } from 'basefyio-js'
const bf = createClient({ projectId: '...', apiKey: '...' })
// Create an entity
await bf.data.createEntity({
logicalName: 'patients',
displayName: 'Patients',
fields: [
{ name: 'firstName', kind: 'scalar', type: 'text', required: true },
{ name: 'lastName', kind: 'scalar', type: 'text', required: true },
{ name: 'address', kind: 'object', children: [
{ name: 'city', kind: 'scalar', type: 'text', required: true },
{ name: 'country', kind: 'scalar', type: 'text', required: true },
]},
{ name: 'tags', kind: 'array', itemSchema: {
name: 'tag', kind: 'scalar', type: 'text'
}},
],
})
// Insert a document
const { data: patient } = await bf.data.collection('patients').insert({
firstName: 'John',
lastName: 'Smith',
address: { city: 'Istanbul', country: 'TR' },
tags: ['cardiology', 'vip'],
})
// Find documents with nested filter
const { data: results } = await bf.data.collection('patients')
.find({ 'address.city': 'Istanbul' })
.sort('_createdAt', 'desc')
.limit(20)
// Get by ID
const { data: doc } = await bf.data.collection('patients').get(patient._id)
// Partial update (merge)
await bf.data.collection('patients').update(patient._id, {
tags: ['cardiology', 'vip', 'follow-up'],
})
// Soft delete
await bf.data.collection('patients').delete(patient._id)
// List entities
const { data: entities } = await bf.data.listEntities()
// Health check
const { data: health } = await bf.data.health()
// => { available: true, reachable: true }Entity Schema System
Entity definitions live in database metadata, not in the document store. Each entity has typed fields that compile to JSON Schema for validation.
Field Kinds
| Kind | Description | Example |
|---|---|---|
scalar | Simple value (text, number, boolean, date, email, phone, url) | firstName: text |
object | Nested object with child fields | address: { city, country } |
array | Array with item schema | tags: [text] |
lookup | Reference to another entity | doctorId → doctors |
media | Rich media (url, dimensions, duration) | avatar: media |
counter | Numeric counter updated via events | views: counter |
attachment | File reference (url, mimeType, size) | report: attachment |
Nested Data Example
// An entity with nested objects and arrays
{
logicalName: 'orders',
fields: [
{ name: 'customer', kind: 'object', children: [
{ name: 'name', kind: 'scalar', type: 'text', required: true },
{ name: 'address', kind: 'object', children: [
{ name: 'city', kind: 'scalar', type: 'text' },
{ name: 'country', kind: 'scalar', type: 'text' },
{ name: 'zip', kind: 'scalar', type: 'text' },
]},
]},
{ name: 'lineItems', kind: 'array', itemSchema: {
name: 'lineItem', kind: 'object', children: [
{ name: 'productId', kind: 'scalar', type: 'text', required: true },
{ name: 'quantity', kind: 'scalar', type: 'number', required: true },
{ name: 'price', kind: 'scalar', type: 'currency' },
]
}},
{ name: 'total', kind: 'scalar', type: 'currency', required: true },
]
}Storage Providers
| Provider | When to Use | Configuration |
|---|---|---|
| NoSQL store | Production — optimized for document workloads, full-text search, KV access | DATA_ENGINE_PROVIDER=nosql |
| database | Development — no extra infrastructure, uses existing project DB | DATA_ENGINE_PROVIDER=database |
| Disabled | Skip Data Engine entirely (existing features unaffected) | DATA_ENGINE_PROVIDER=disabled |
Configuration
| Variable | Default | Description |
|---|---|---|
DATA_ENGINE_PROVIDER | disabled | Provider: nosql, database, or disabled |
NOSQL_CONNSTR | — | NoSQL store connection string |
NOSQL_USERNAME | — | Store admin username |
NOSQL_PASSWORD | — | Store admin password |
DATA_ENGINE_CONTAINER | basefyio-apps | Top-level container name |
DATA_ENGINE_NAMESPACE | projects | Default namespace |
DATA_ENGINE_MAX_DOC_KB | 1024 | Max document size in KB |
DATA_ENGINE_MAX_NESTING_DEPTH | 8 | Max schema nesting depth |
DATA_ENGINE_MAX_ARRAY_ITEMS | 1000 | Max array items per field |
Admin Dashboard — Data Tab
Each project's Data tab in the dashboard provides:
- Entity sidebar — Browse all entities, see AI-generated badges, search by name
- Document browser — Expandable JSON cards with envelope metadata (version, status, timestamps)
- JSON filter — Filter documents with JSON syntax, e.g.
{"status":"active"} - Insert / Edit / Delete — Full CRUD with JSON editors
- Pagination — Server-side, 50 documents per page
- Engine label — Read-only "Basefyio Data Engine" badge