Skip to content

App Builder Schema

Complete JSON schema reference for application definitions

The root structure for an App Builder application:

{
"id": "my-app",
"name": "My Application",
"description": "Application description",
"version": "1.0.0",
"pages": [],
"navigation": {},
"permissions": {},
"globalDataSources": [],
"globalVariables": {}
}
FieldTypeRequiredDescription
idstringYesUnique application identifier
namestringYesDisplay name
descriptionstringNoApplication description
versionstringYesSemantic version
pagesPageDefinition[]YesApplication pages
navigationNavigationConfigNoSidebar and header configuration
permissionsPermissionConfigNoApp-level access control
globalDataSourcesDataSource[]NoData sources available to all pages
globalVariablesobjectNoInitial variables for all pages

{
"id": "dashboard",
"title": "Dashboard",
"path": "/",
"layout": {},
"dataSources": [],
"variables": {},
"launchWorkflowId": "load_dashboard_data",
"launchWorkflowParams": {},
"permission": {}
}
FieldTypeRequiredDescription
idstringYesUnique page identifier
titlestringYesPage title (shown in browser tab)
pathstringYesURL path (e.g., /, /users/:id)
layoutLayoutContainerYesRoot layout for page content
dataSourcesDataSource[]NoPage-specific data sources
variablesobjectNoInitial page variables
launchWorkflowIdstringNoWorkflow to run on page mount
launchWorkflowParamsobjectNoParameters for launch workflow
permissionPagePermissionNoPage access control

Use :param syntax for dynamic routes:

{ "path": "/users/:userId" }
{ "path": "/org/:orgId/projects/:projectId" }

Access in expressions: {{ params.userId }}


{
"type": "column",
"gap": 16,
"padding": 24,
"align": "stretch",
"justify": "start",
"columns": 3,
"children": []
}
FieldTypeRequiredDescription
typestringYesrow, column, or grid
gapnumberNoSpace between children (pixels)
paddingnumberNoInternal padding (pixels)
alignstringNoCross-axis alignment
justifystringNoMain-axis alignment
columnsnumberNoGrid columns (grid type only)
childrenarrayNoNested layouts or components

Align values: start, center, end, stretch

Justify values: start, center, end, between, around


Base structure for all components:

{
"id": "component-1",
"type": "heading",
"visible": "{{ user.isActive }}",
"width": "1/2",
"props": {}
}
FieldTypeRequiredDescription
idstringYesUnique component identifier
typestringYesComponent type (see Components Reference)
visiblestringNoVisibility expression
widthstringNoComponent width
propsobjectYesComponent-specific properties

Width values: auto, full, 1/2, 1/3, 1/4, 2/3, 3/4


{
"id": "customers",
"type": "workflow",
"workflowId": "get_customers",
"inputParams": {
"status": "active"
},
"autoRefresh": false,
"refreshInterval": 30000
}
FieldTypeRequiredDescription
idstringYesData source identifier
typestringYesworkflow, data-provider, api, static, computed
workflowIdstringConditionalWorkflow ID (for workflow type)
dataProviderIdstringConditionalData provider ID (for data-provider type)
endpointstringConditionalAPI URL (for api type)
dataanyConditionalStatic data (for static type)
expressionstringConditionalExpression (for computed type)
inputParamsobjectNoParameters (supports expressions)
autoRefreshbooleanNoAuto-refresh enabled
refreshIntervalnumberNoRefresh interval in milliseconds

workflow: Execute a workflow and use its return value:

{
"id": "orders",
"type": "workflow",
"workflowId": "get_orders",
"inputParams": { "userId": "{{ user.id }}" }
}

data-provider: Use a registered data provider:

{
"id": "departments",
"type": "data-provider",
"dataProviderId": "get_departments"
}

static: Inline data:

{
"id": "statusOptions",
"type": "static",
"data": [
{ "label": "Active", "value": "active" },
{ "label": "Inactive", "value": "inactive" }
]
}

{
"showHeader": true,
"showSidebar": true,
"logoUrl": "https://example.com/logo.png",
"brandColor": "#4F46E5",
"sidebar": []
}
FieldTypeDescription
showHeaderbooleanShow application header
showSidebarbooleanShow navigation sidebar
logoUrlstringLogo image URL
brandColorstringPrimary brand color (hex)
sidebarNavItem[]Sidebar navigation items
{
"id": "nav-dashboard",
"label": "Dashboard",
"icon": "home",
"path": "/",
"visible": "{{ user.role != 'guest' }}",
"order": 1,
"isSection": false,
"children": []
}
FieldTypeDescription
idstringUnique nav item ID
labelstringDisplay text
iconstringLucide icon name
pathstringNavigation path
visiblestringVisibility expression
ordernumberSort order
isSectionbooleanRender as section header
childrenNavItem[]Nested nav items

Section Example:

{
"id": "admin-section",
"label": "Administration",
"isSection": true,
"visible": "{{ user.role == 'admin' }}",
"children": [
{ "id": "users", "label": "Users", "icon": "users", "path": "/admin/users" },
{ "id": "settings", "label": "Settings", "icon": "settings", "path": "/admin/settings" }
]
}

Application-level permissions:

{
"public": false,
"defaultLevel": "none",
"rules": [
{ "role": "admin", "level": "admin" },
{ "role": "manager", "level": "edit" },
{ "role": "*", "level": "view" }
]
}
FieldTypeDescription
publicbooleanAllow unauthenticated access
defaultLevelstringDefault permission level
rulesPermissionRule[]Role-based permission rules
{ "role": "admin", "level": "admin" }
FieldTypeDescription
rolestringRole name or * for all authenticated users
levelstringnone, view, edit, admin

Page-level access control:

{
"allowedRoles": ["admin", "manager"],
"accessExpression": "{{ user.department == 'engineering' }}",
"redirectTo": "/access-denied"
}
FieldTypeDescription
allowedRolesstring[]Roles that can access (* for all authenticated)
accessExpressionstringExpression that must evaluate to true
redirectTostringRedirect path if access denied

{
"type": "navigate",
"navigateTo": "/customers/{{ workflow.result.id }}"
}
{
"type": "set-variable",
"variableName": "lastCreated",
"variableValue": "{{ workflow.result }}"
}
{
"type": "refresh-table",
"dataSourceKey": "customers"
}
FieldTypeApplies ToDescription
typestringAllnavigate, set-variable, refresh-table
navigateTostringnavigateTarget path
variableNamestringset-variableVariable to set
variableValueanyset-variableValue to assign
dataSourceKeystringrefresh-tableData source ID

{
"key": "user.email",
"header": "Email",
"type": "text",
"width": 200,
"sortable": true,
"badgeColors": {}
}
FieldTypeDescription
keystringData field path (dot notation supported)
headerstringColumn header text
typestringtext, number, date, badge
widthnumber/stringColumn width
sortablebooleanEnable column sorting
badgeColorsobjectValue-to-color mapping (for badge type)

{
"label": "Delete",
"icon": "trash",
"variant": "destructive",
"visible": "{{ row.canDelete }}",
"disabled": "{{ row.isLocked }}",
"onClick": {
"type": "workflow",
"workflowId": "delete_item",
"actionParams": { "id": "{{ row.id }}" }
},
"confirm": {
"title": "Confirm Delete",
"message": "Delete {{ row.name }}?",
"confirmLabel": "Delete",
"cancelLabel": "Cancel"
}
}
FieldTypeDescription
labelstringAction button label
iconstringLucide icon name
variantstringdefault, destructive, outline, ghost
visiblestringVisibility expression
disabledstringDisabled expression
onClickobjectAction configuration
confirmConfirmConfigConfirmation dialog

{
"title": "Confirm Action",
"message": "Are you sure?",
"confirmLabel": "Confirm",
"cancelLabel": "Cancel"
}
FieldTypeDefaultDescription
titlestringrequiredDialog title
messagestringrequiredConfirmation message
confirmLabelstringConfirmConfirm button text
cancelLabelstringCancelCancel button text

{ "label": "Active", "value": "active" }
FieldTypeDescription
labelstringDisplay text
valuestringOption value

{
"id": "customer-portal",
"name": "Customer Portal",
"version": "1.0.0",
"permissions": {
"public": false,
"rules": [
{ "role": "*", "level": "view" }
]
},
"navigation": {
"showSidebar": true,
"sidebar": [
{ "id": "home", "label": "Dashboard", "icon": "home", "path": "/" },
{ "id": "customers", "label": "Customers", "icon": "users", "path": "/customers" }
]
},
"pages": [
{
"id": "dashboard",
"title": "Dashboard",
"path": "/",
"dataSources": [
{
"id": "stats",
"type": "workflow",
"workflowId": "get_dashboard_stats"
}
],
"layout": {
"type": "column",
"gap": 24,
"padding": 24,
"children": [
{
"id": "welcome",
"type": "heading",
"props": {
"text": "Welcome, {{ user.name }}",
"level": 1
}
},
{
"type": "grid",
"columns": 3,
"gap": 16,
"children": [
{
"id": "stat-customers",
"type": "stat-card",
"props": {
"title": "Total Customers",
"value": "{{ data.stats.customerCount }}",
"icon": "users"
}
},
{
"id": "stat-revenue",
"type": "stat-card",
"props": {
"title": "Revenue",
"value": "${{ data.stats.revenue }}",
"icon": "dollar-sign"
}
},
{
"id": "stat-orders",
"type": "stat-card",
"props": {
"title": "Active Orders",
"value": "{{ data.stats.activeOrders }}",
"icon": "shopping-cart"
}
}
]
}
]
}
},
{
"id": "customers",
"title": "Customers",
"path": "/customers",
"dataSources": [
{
"id": "customers",
"type": "workflow",
"workflowId": "list_customers"
}
],
"layout": {
"type": "column",
"gap": 16,
"padding": 24,
"children": [
{
"type": "row",
"justify": "between",
"align": "center",
"children": [
{
"id": "title",
"type": "heading",
"props": { "text": "Customers", "level": 1 }
},
{
"id": "add-btn",
"type": "button",
"props": {
"label": "Add Customer",
"actionType": "navigate",
"navigateTo": "/customers/new"
}
}
]
},
{
"id": "table",
"type": "data-table",
"props": {
"dataSource": "customers",
"searchable": true,
"paginated": true,
"columns": [
{ "key": "name", "header": "Name", "sortable": true },
{ "key": "email", "header": "Email" },
{ "key": "status", "header": "Status", "type": "badge" }
],
"onRowClick": {
"type": "navigate",
"navigateTo": "/customers/{{ row.id }}"
},
"rowActions": [
{
"label": "Edit",
"icon": "pencil",
"onClick": {
"type": "navigate",
"navigateTo": "/customers/{{ row.id }}/edit"
}
}
]
}
}
]
}
}
]
}

TypeValues
ComponentTypeheading, text, html, card, divider, spacer, button, stat-card, image, badge, progress, data-table, tabs, file-viewer, modal, text-input, number-input, select, checkbox, form-embed, form-group
LayoutTyperow, column, grid
ActionTypenavigate, workflow, submit, set-variable, refresh-table, custom
PermissionLevelnone, view, edit, admin
ButtonVariantdefault, destructive, outline, secondary, ghost, link
ButtonSizedefault, sm, lg
ColumnTypetext, number, date, badge
Widthauto, full, 1/2, 1/3, 1/4, 2/3, 3/4
Alignstart, center, end, stretch
Justifystart, center, end, between, around