Configuration Reference
There is one config file: config/ui5.php. Core owns the base keys, the SDK contributes its own on top, and your host redeclares whichever it wants to change. Nothing is published, nothing is forked.
Configuration shows the file a host actually writes. This page is the complete key list — what each key is for, what the default is, and who owns it.
How the merge works
The SDK calls mergeConfigFrom(…, 'ui5') in register(). Laravel's merge is shallow: your top-level key replaces the package's entirely, it does not merge into it. So redeclaring shell means redeclaring the whole shell array, not just the one nested value you wanted to change.
Shallow merge, one level deep
A host cannot override a single nested key. If you need one value inside shell.manifest, copy the whole block from the SDK's config.php into your own file and edit it there. Known, filed, and the reason the SDK's blocks are documented key by key in the package file.
Core's keys
| Key | Default | What it does |
|---|---|---|
version | an OpenUI5 version tag | The default OpenUI5 version for every app, unless the app overrides it. Used at runtime and when scaffolding. |
meta | [] | Key/value pairs stamped into the generator block of every generated manifest.json. |
routes | [] | Laravel route names exposed to the manifest as laravel.ui5.routes — e.g. login, logout, home. Resolved through route(). |
registry | Ui5Registry::class | The artifact registry. A host on the SDK sets SdkRegistry::class. |
context_factory | CoreContextFactory::class | Builds the per-request context. A host on the SDK sets the SDK's factory — that is what upgrades Ui5Context to SdkContext. |
middleware | see below | The artifact route stack. |
odata_middleware | see below | The OData route stack. |
modules | [] | The explicit list of your business modules. Only what is listed here is registered. |
auth_enabled | env('ENABLE_AUTH_4_UI5', true) | The authentication gate. false makes it inert — local development only. |
artifact_resolvers | [PathBasedArtifactResolver::class] | The ordered chain mapping a request path to an artifact. |
Three of those are where an SDK host differs from a Core-only host, and all three are in the quickstart: registry, context_factory, and the two middleware arrays. A fourth is easy to miss — artifact_resolvers needs two SDK entries appended, or the shell and export routes resolve nothing:
'artifact_resolvers' => [
\LaravelUi5\Core\Runtime\PathBasedArtifactResolver::class,
\LaravelUi5\Sdk\Platform\Context\ShellContextArtifactResolver::class,
\LaravelUi5\Sdk\Export\ExportArtifactResolver::class,
],The SDK's keys
system_actor_id
'system_actor_id' => (int) env('UI5_SYSTEM_ACTOR_ID', 1),The partner id of the installation's single non-human actor — the platform owner stamped as the writer on actor-less writes (a scheduled job, a webhook, ui5:sync seeding set_by). The default follows the operator convention, partner #1, which is what ui5:intake creates. The resolver loads it and fails loud if it is missing or is not a platform-level partner. See the system actor.
navigation_service
'navigation_service' => DefaultNavigationService::class,DefaultNavigationService builds the navigation tree from the registry in memory. CachedNavigationService reads the file ui5:nav compiled — bind it in production, and run ui5:nav before the first request or it throws. See caching and performance.
export
'export' => [
'max_rows' => 500,
'writers' => ['csv' => CsvExportWriter::class],
],max_rows is the guard the export controller checks before streaming — a wider export is a 422 telling the user to narrow the list. writers maps a format token to its writer; add xlsx here with your own writer, and your spreadsheet library stays in your composer.json. See table export.
context
The map that builds context.json. Each key is a ContextServiceInterface::KEY_* constant, each value a contributor — and a contributor fills exactly one key, never merges into another's.
Shipped keys: actor and principal (the same IdentityContextContributor, wired twice with a config flag saying which partner to project), abilities, actions (from discovery.context), navigation, and settings and weave (both appended by the provider itself).
The navigation entry is the one with real structure inside it — a projector, a branding block with CI and home candidates, a body pipeline of contributors, an identity block and a footer. The LeanShell's navigation manager requires context.navigation at init; without it the shell dies with shell_initialization_failed.
discovery
Two assembled discovery services — discovery.context and discovery.search, both container singletons. Each declares the result key it lands under, the route it is reachable at, and a map of collectors, each collector paired with an authorizer.
The separation this encodes is load-bearing: a collector finds things, an authorizer constrains the query. Collectors never query security tables. See visibility and CmdK.
shell
Two halves.
shell.manifest is the client-side knob block that reaches the LeanShell: the log level (UI5_SHELL_LOG_LEVEL), the intent-dispatcher URL template, the command palette's placeholder and hotkeys, the search manager's minChars, the help manager's default locale, and the close hotkeys for the help viewer and nav options.
The intent dispatcher is a template, /ui5/shell/{slug}/intend.json, not a baked route() URL — config is merged at register() time, before routes exist, so the client fills in {slug} itself.
shell.services is the map of shell contributors, each contributing exactly one root node to the shell manifest. discovery.search carries a limit here.
intents
'intents' => [],Your intent capabilities, as IntentClass => ['authorizer' => …, 'handler' => …]. Empty by default because the SDK's own seven intents are appended by the provider rather than listed here — so redeclaring this key adds to them rather than replacing them. See intent dispatch.
help
'help' => ['markdown' => ['table' => [...]]],Passed verbatim to the CommonMark environment factory. Only the Table extension is configured. Heading permalinks are deliberately not registered — help pages must not carry ¶ anchors before every heading, they pollute the viewer. To change the extension set, rebind MarkdownEnvironmentFactoryInterface rather than reaching for a config key that does not exist.
Environment variables
| Variable | Reaches | Default |
|---|---|---|
ENABLE_AUTH_4_UI5 | ui5.auth_enabled | true |
UI5_SYSTEM_ACTOR_ID | ui5.system_actor_id | 1 |
UI5_SHELL_LOG_LEVEL | ui5.shell.manifest.logLevel | debug |
Set UI5_SHELL_LOG_LEVEL to something quieter than debug in production.
Two keys that are not config
Worth naming, because people look for them:
- There is no
sdk.*namespace. Everything the SDK reads lives underui5.*. A key the vendor does not read is a key nobody maintains. - There is no list of your apps' abilities, roles or settings. Those are declared in code with attributes and land in the database through
ui5:sync. Configuration wires services; declarations describe artifacts.