Admin screens defined in JSON, not XML
Magento's UI components mean XML, KnockoutJS and a build step. Nebula replaces that with declarative JSON: a form, a grid or a reusable snippet is a single schema-backed file your editor can autocomplete and your CI can lint.
The JSON Engine
Admin screens as JSON, not XML
Nebula renders forms, grids and reusable snippets from plain JSON definitions. Each one is validated against a published JSON Schema, so your editor autocompletes it and CI catches mistakes before they ship.
{
"id": "email_template_edit",
"acl": "Magento_Email::template",
"dataSource": {
"provider": "email.template.form",
"config": { "identifierParam": "id" }
},
"settings": {
"title": "Email Template",
"identifierField": "template_id",
"saveUrl": "adminhtml/email_template/save",
"backUrl": "adminhtml/email_template/index"
},
"fieldsets": {
"general": {
"label": "Template Information",
"open": true,
"fields": {
"template_code": { "label": "Template Name", "type": "text", "required": true, "position": 10 },
"template_subject": { "label": "Subject", "type": "text", "required": true, "position": 20 },
"template_text": { "label": "Content", "type": "textarea", "required": true, "position": 30 }
}
}
}
}What it does
Fieldsets, field types, validation, data source and save/back URLs — the whole edit screen as one JSON file. No UI-component XML, no KnockoutJS.
Field types
Validate before you ship
bin/magento nebula:lintLints every definition against its schema. Add --fix to auto-format, sort and position fields.
Extensibility
Replace a section — without forking the screen
Any module can drop a JSON file with the same id into its view/adminhtml/ folder. Nebula deep-merges every fragment in module load order, so you can add, replace or remove fields, columns and whole sections — and point a section at your own snippet — without editing the original definition.
It's exactly how Nebula handles product types: configurable and bundle products overlay the base catalog_product_edit form and — for their type only (condition: type_id) — swap the simple price area for their own variation and bundle-item sections, each rendered by its own snippet.
Overlay: swap a section by product type
{
"layout": [
{
"id": "main_row",
"children": [
{
"id": "configurable_column",
"type": "column",
"width": "1/2",
"condition": { "type_id": "configurable" },
"children": [
{
"id": "configurable_variations",
"type": "section",
"label": "Configurable Variations",
"renderer": "snippet.configurable_options"
}
]
}
]
}
]
}Same id as the base form, so it merges in. The conditional column renders only for configurable products — replacing the default price layout with a variations section.
Remove a field
{
"fieldsets": {
"advanced_pricing": {
"fields": {
"tier_price": { "$remove": true }
}
}
}
}{ "$remove": true } drops a field, column or section the base shipped.
Swap a section's template
{
"id": "configurable_options",
"template": "Acme_Catalog::snippet/my_configurable_options.phtml"
}Re-declare a snippet id to render the section with your own phtml.