Skip to content

Working with laravel.ui5 Manifest Fragments

What is laravel.ui5?

The laravel.ui5 section inside the manifest.json is a Laravel-specific extension that provides backend-side metadata to your UI5 applications.

It describes features such as:

  • Registered backend actions (Ui5Action) and resource endpoints (Ui5Resource)
  • Dashboards and reports the module owns, as id → url maps
  • Laravel-defined app routes (e.g. login, logout)
  • Resolved settings and slot defaults
  • Shell configuration and cross-cutting platform facts (infra)

This section is not maintained in the frontend, but fully generated by Laravel.

How does it work?

Any UI5 app names a manifest class: getLaravelUiManifest() returns the class-string of a LaravelUi5ManifestInterface implementation, which Core resolves from the container.

This class is responsible for returning the full fragment that will be inserted into the laravel.ui5 root node of your manifest.json.

What comes out of the box?

The base implementation already includes the following keys:

The reserved keys are defined once, in LaravelUi5ManifestKeys, and rendered in this order:

KeyDescription
metaInfo about app, tenant or environment — version, license state, branding flags
routesLaravel route names the frontend may consume (login, logout, profile)
actionsBackend actions callable via LaravelUi5.call(...)
resourcesResource endpoints callable via LaravelUi5.get(...)
settingsSettings exposed to the frontend — feature toggles, UI preferences
vendorSandbox for vendor-specific metadata; Core prescribes no schema here
shellConfiguration for the global Shell layer (navigation, help, search, shortcuts)
dashboardsdashboard-id → manifest-url, resolved by <lux:dashboard>; per-module scope
reportsreport-id → { url, params }, resolved by <lux:Report>; per-module scope
infraStatic, cross-cutting platform facts, namespaced by contributing module

You don’t need to define these manually. The framework takes care of them.

Two of them are not yours to fill from here. dashboards and reports are injected by Core from the registry — see Core injects the OData and artifact maps. And infra has a single door: a module implementing Ui5InfrastructureContributorInterface, never contributeFragment(). It carries platform facts that must be identical in every app's manifest, which is exactly why it is not per-app editable — see Infrastructure Contributions.

Extending it: contributeFragment()

Every module's manifest class extends AbstractManifest and implements one abstract method. ui5:app scaffolds it for you, returning an empty array:

php
use LaravelUi5\Core\Ui5\AbstractManifest;

class OffersManifest extends AbstractManifest
{
    protected function contributeFragment(string $module): array
    {
        return [];
    }
}

The $module argument is the contributing module's namespace — you need it to namespace a vendor contribution (below).

You may contribute to exactly two keys

This is the part to internalise before writing anything here:

KeyWhy it is open
routesa module legitimately owns named URLs the frontend needs — logout, legal pages, a branding asset
vendora namespaced sandbox for whatever your module wants to tell its own frontend

Every other key is built by Core and closed to contribution. meta, actions, resources, settings, shell, dashboards, reports and infra are all derived from the registry — they are the framework reporting what it found, not a place to write.

That is enforced, not advisory. Contributing anything else fails loudly while the manifest is being built:

  • a key that is not in LaravelUi5ManifestKeysInvalidArgumentException: Unknown manifest key [foo]
  • a real but closed key → LogicException: Manifest key [settings] does not allow contributions

Contributing routes

The laravelui5/auth package is the reference case — it publishes its own branding asset and a set of optional legal routes:

php
use Illuminate\Support\Facades\Route;
use LaravelUi5\Core\Ui5\AbstractManifest;
use LaravelUi5\Core\Ui5\Capabilities\LaravelUi5ManifestKeys;

class AuthManifest extends AbstractManifest
{
    protected function contributeFragment(string $module): array
    {
        return [
            LaravelUi5ManifestKeys::ROUTES => [
                'logo'    => asset('vendor/laravelui5/auth/logo-full.svg'),
                'terms'   => Route::has('terms') ? route('terms') : null,
                'privacy' => Route::has('privacy') ? route('privacy') : null,
            ],
        ];
    }
}

Contributed routes are merged into the routes map Core built from config('ui5.routes') — they add to it, they do not replace it.

Contributing vendor data

Vendor contributions must be namespaced by the contributing module, so two packages can both write here without colliding:

php
protected function contributeFragment(string $module): array
{
    return [
        LaravelUi5ManifestKeys::VENDOR => [
            $module => [
                'featureFlags' => ['timesheet' => true],
                'branding'     => ['accent' => '#0a6ed1'],
            ],
        ],
    ];
}

Core prescribes no schema inside your namespace — it is yours.

📝 Where roles and abilities actually live. Authorization is not a Core concern: Core is auth-blind and carries no user, role, or ability model. On an SDK host they reach the manifest through the SDK's own layer, never through this hook.

Safe by design

An empty key is dropped rather than serialised, so a manifest never carries a bare "actions": {}. And the two failure modes above mean a typo or an over-reaching contribution surfaces as an exception naming the offending key — never as a silently ignored section you discover missing in the browser.

Sample output

Note that actions and resources are keyed by the artifact's full namespace, and their URLs carry the @{version} coordinate plus one path segment per #[Parameter] the handler declares:

jsonc
{
  "laravel.ui5": {
    "meta": {
      "generator": "LaravelUi5 Core"
    },
    "routes": {
      "login": "https://offers.test/login",
      "logout": "https://offers.test/logout"
    },
    "actions": {
      "com.acme.offers.actions.approve": {
        "method": "POST",
        "url": "/ui5/api/com/acme/offers/actions/[email protected]/{offer}"
      }
    },
    "resources": {
      "com.acme.offers.resources.header": {
        "method": "GET",
        "url": "/ui5/resource/com/acme/offers/resources/[email protected]"
      }
    },
    "settings": {
      "maxItems": 10
    },
    "vendor": {
      "com.acme.offers": {
        "featureFlags": { "timesheet": true }
      }
    },
    "infra": {
      "core": { "slots": { "currency": { "type": "String", "default": "EUR", "editable": "User", "note": "…" } } }
    }
  }
}

Keys with nothing in them are filtered out before serialisation, so a real manifest shows only the sections that actually have content.

Summary

The laravel.ui5 manifest fragment is the unified place for Laravel-to-UI5 metadata. It is:

  • Server-generated — Core builds it from the registry, so it cannot drift from what is actually registered
  • Validated — an unknown or closed key throws rather than being ignored
  • Extensible at exactly two seams, routes and vendor
  • Generated by Core, and extended by the SDK where it adds its own keys

If your UI5 app needs to tell its frontend something Core does not already report, the vendor namespace is the place. Permissions are not that something — they belong to the SDK's authorization layer.