Skip to content

Configuration

After publishing the config with php artisan vendor:publish --tag="lattice-config", you can tune Lattice in config/lattice.php.

Lattice automatically discovers form, table, fragment, action, bulk action, remote source, layout, and page definitions by scanning the configured paths for classes carrying the matching attribute:

'discover' => [
base_path('app'),
],

List every path Lattice should scan. Discovery walks the files directly, so no namespace mapping is needed.

The cached discovery manifest (php artisan lattice:discover-cache) is written to bootstrap/cache/lattice.php; set 'discovery' => ['cache_path' => …] to relocate it.

Instead of (or in addition to) discovery, register definition classes at runtime through the Lattice facade — useful from a service provider:

use Lattice\Core\Facades\Lattice;
Lattice::forms([\App\Forms\ContactForm::class]);
Lattice::tables([\App\Tables\UsersTable::class]);

The same method exists for fragments, actions, bulkActions, layouts, pages, and remoteSources.

Each definition type is served by a dedicated named route with its own middleware stack. The defaults all run behind web and auth:

Type Route name Path Middleware
Forms lattice.forms.handle lattice/forms/{form} ['web', 'auth']
Tables lattice.tables.show lattice/tables/{table} ['web', 'auth']
Fragments lattice.fragments.show lattice/fragments/{fragment} ['web', 'auth']
Actions lattice.actions.handle lattice/actions/{action} ['web', 'auth']
Bulk actions lattice.bulk-actions.handle lattice/bulk-actions/{bulkAction} ['web', 'auth']
Remote sources lattice.remote-sources.token lattice/remote-sources/{source}/token ['web', 'auth']
Notifications lattice.notifications.* lattice/notifications ['web', 'auth']

Change the middleware stack per type:

'forms' => [
'middleware' => ['web', 'auth'],
],

Endpoint URLs are minted from the named routes, so they honour your app’s base path — subdirectory installs included. To serve a type from a different path, register your own route under the same name after Lattice’s routes load; the components pick it up automatically.

Every page’s components call back into the same endpoints, behind the same middleware. When part of your app signs users in differently — a customer portal on the customer guard, an account page on its own domain behind a tenant-resolving middleware — mount the endpoints a second time for it with Lattice::endpoints() from a service provider’s boot():

use Lattice\Core\Facades\Lattice;
Lattice::endpoints('portal', prefix: 'portal/lattice', middleware: ['web', 'auth:customer']);

The area gets the full set of component endpoints — forms, tables, actions, bulk actions, fragments, remote-source tokens, the ref refresh, and the board, calendar, tree, and block-editor endpoints of the installed packages — below its prefix, behind exactly the middleware you pass, named lattice.{area}.… (lattice.portal.forms.handle). The default routes stay as they are. Notifications and search are app-wide services, not component endpoints, and keep their own routes.

A page opts in with endpoints on its #[AsPage] attribute:

#[AsPage(route: '/portal', middleware: 'auth:customer', endpoints: 'portal')]
final class PortalPage extends Page {}

A page you cannot annotate — one a package renders from its own controller — joins the area through the UseEndpointArea middleware on its route instead:

use Lattice\Http\Middleware\UseEndpointArea;
Route::middleware(['web', 'auth:customer', UseEndpointArea::class.':portal'])->group(/* … */);

Every endpoint minted while that page renders points into the area, and so does every endpoint a request to the area builds in turn — a lazy table’s row actions, a fragment’s form, a modal’s form. The signed reference of each component is bound to the area it was minted for: replayed against another area’s endpoints — or refreshed through another area’s ref refresh — it is refused with a 403, so a request can never escape the middleware its page was served behind.

The notifications block also takes per_page, polling_interval, and prune_after_days — see Notifications.

File uploads are stored through Laravel’s filesystem. Pending uploads live under a temporary prefix and are served with short-lived signed URLs until the form is submitted:

'files' => [
'disk' => env('LATTICE_FILES_DISK', 'public'),
'temp_prefix' => 'tmp',
'url_ttl' => 5,
],
  • disk — the storage disk uploads are written to.
  • temp_prefix — the directory pending (not-yet-finalized) uploads are placed in.
  • url_ttl — how long, in minutes, a temporary signed file URL stays valid.

The locales Lattice exposes to the client and the i18n runtime:

'i18n' => [
'locales' => ['en'],
'preload_locales' => [],
],
  • locales — the locales available to the application.
  • preload_locales — locales whose translations are bundled into the initial page payload instead of being fetched on demand. Leave empty to load every locale lazily.

Toggles the realtime broadcasting layer. When disabled, page listeners are not serialized to the client:

'realtime' => [
'enabled' => env('LATTICE_REALTIME_ENABLED', true),
],

Component references embedded in the page payload are signed. security.ref_lifetime controls how long, in minutes, a signed reference stays valid:

'security' => [
'ref_lifetime' => 30,
],

The 'frontend' block configures the prebuilt-asset path, precompiled plugin URLs, theme variables, and Echo settings for the no-build installation — see No-Build Installation.

Where php artisan lattice:typescript writes the generated type definitions, and the module name they are published under (generating types for custom wire types needs the suggested dev dependency: composer require --dev spatie/laravel-typescript-transformer):

'typescript' => [
'output' => resource_path('js/lattice/generated.d.ts'),
'module' => '@lattice-php/core',
],